Welcome to the "All in one" view page of the Wikibooks's Microsoft certification exam 70-536 study guide. Considering it's size, this page was not configured for editing (please usemain page).
Welcome to the 'Microsoft .NET Framework 2.0 Application Development Foundation' module.
This book provides extensive "textbook like" coverage of the exam objectives associated with exam 70-536 of the Microsoftcertification program. Those objectives cover the basic .NET class libraries and the interaction of a program with the .NET execution environment.
Please give us your feedback on the module so we can improve it (seediscussion page).
The preface contains information relevant to the context of the document, authors, wikibooks, etc. You can skip to theIntroduction if you are primarily interested in the module content.
The audience for this study guide are software developers professionally interested in the .NET framework.Microsoft states in the Exam (70-536)preparation guide that "Candidates should have at least two to three years of experience developing Web-based, Microsoft Windows-based, or distributed applications by using the .NET Framework 1.0, the .NET Framework 1.1, and the .NET Framework 2.0. Candidates should have a working knowledge of Visual Studio 2005.".
For this study guide, we will just assume that readers know at least one of the .NET languages (VB.NET, C#, etc.), have access to Visual Studio and have some experience working with it.
Please note that the .NET platform is quite extensive and that a basic understanding of computer science is also assumed. For example, we will briefly discuss how object-orientation principles are implemented in the framework (from a developer point of view) but not the principles themselves, where do they come from, what specific problems they address, etc.
Wikibooks has other books both on VB, C# and .NET that are more introductory in nature:
Finally, by "professionally interested" we refer to the fact that this book, along with the other certification study guides, provides an extensive coverage of the framework and demands a significant study time. So anybody that wants to get that kind of coverage and has some time to spare can join in!
This module is far from over! Please do not hesitate to improve it as you see fit.
Just a couple of pointers though if you are a new contributor to wikibooks:
Current information on the exam can be found atMSDN Exam Information
This module is the study guide for the first exam (70-536) for obtaining many Microsoft certifications:
William "Scott" Baker (User:Scott98390)
Please note that it is not wikibook's policy to have link only pages or pages with very few text. The preferred way is to have continuous textbooks that can be read from start to finish. The first contributions to this module where in the form of separate pages for each third or forth level exam objectives. This gave way to numerous pages that were merged into more consistent global pages. For links only page, this process had the adverse side effect of losing references to contributions made to those pages. For pages with text the change history were moved to the merged page.
This study guidedoes not aim at replacing the other resources that exist to get prepared to pass the 70-536 exam:
What wedo provide though, even at this document's grossly incomplete stage, is:
The most difficult aspect of a book like this one is to keep a balance between having enough content to cover and explain every objective of the exam and not too much content because reading and studying time should be kept to a manageable level. Furthermore, there is no reason to cover content here that is not directly related to exam objectives.
Finally, as part of the Wikimedia family (Wikipedia and all) the Wikibooks project has very high ethics on copyrights and general quality. Do not hesitate to correct if you find anything "wrong" in any way.
This module is structured around the objectives set by Microsoft for the 70-536 Exam. Chapters 3 to 9 represents each of the 7 major objective categories of the exam.
The idea behind sticking to the exam "official" objectives is that we assume that somehow the certification provider (Microsoft) has some understanding of the product (.NET) and can state what is important to know about it.
For each chapter:
Eventually, we would like to have:
As of December 7, 2007:
Some sections are relatively advanced and others are awaiting your contributions. The more advanced sections are not all at the beginning of the module.
![]() | Wikipedia has related information at.NET Framework |
In the certification paths where exam 70-536 "Microsoft .NET Framework 2.0Application Development Foundation" is present, it represents the first step of the certification process. It is thus natural to start this first study guide with a short discussion of the framework as a whole.
The definition onMSDN .NET main page is: "The .NET Framework is Microsoft's managed code programming model for building applications on Windows clients, servers, and mobile or embedded devices. Developers use .NET to build applications of many types: Web applications, server applications, smart client applications, console applications, database applications, and more".
Wikipedia's definition is: "The Microsoft .NET Framework is a software component included with the Microsoft Windows operating system. It provides a large body of pre-coded solutions to common software development requirements, and manages the execution of programs written specifically for the framework. The .NET Framework is intended to be used by most new applications created for the Windows platform"
The problem with Microsoft's definition is that it refers to a "managed code programming model" which is still Microsoft terminology. The best definition for it: "Managed code is code that has its execution managed by the .NET Framework Common Language Runtime" (see Brad Adams blog onMSDN).
Wikipedia's definition points to the two more important aspects from a developer point of view:
Those two main characteristics parallel those of the Java environment, which is the main competitor to the .NET framework. This module tries to help you learn the .NET framework. It will not address the .NET vs Java comparisons and discussions.
The image on the right is taken from the Wikipedia article on the .NET framework (see above).
It describes the process followed by a program written in a .NET compatible language from source code to execution. The important difference with that and more conventional programming languages (ex. C++) is the fact that the program is compiled twice. The first compilation is done from the original language to a "common intermediate language" (CIL). This is what actually goes "in" an assembly.
The second compilation is done from the CIL to machine code. This compilation is usually performed automatically by the "just-in-time" (JIT) compiler. It is also possible to use the Native Image Generator (ngen) utility to create the machine code in advance of runtime.
This architecture has many direct implications for the subjects of this book. Among them:
We could continue like that for a long time. The point we want to make here is that a developer has much to gain from a detailed understanding of the platform, even if it is not directly mentioned as an objective of the exam.
If you want to read on the framework in Microsoft documentation you can seeMSDN.
The last thing we will note here is that the common language runtime (CLR) can execute in different contexts:
By default, examples in this book will use standalone executables. This is just because they are more easy to deploy for very simple programs. This does not imply that Windows applications are preferable to web applications.
The image on the right, also taken from Wikipedia, gives a simplified but clear view of the functional components of the framework.
This book (and the related exam) deals with the "Base Class Library" component and the basic relations of a program with the "Common Language Runtime" component.
The book does not cover ASP.NET, ADO.NET, WF or any other more specialized components.
We can say that we extensively cover the basics but that we shallowly cover the framework itself.
The relations with the common language runtime include such things as:
The base class library includes
All in all they are kind of "dry" topics. This idea of starting with an extensive coverage of the basics is certainly not the most interesting learning pattern for a beginner. This is why we advise real beginners to start with more adequate material.
One last note about the framework "stack" is that new versions tend to add new components instead of "redoing" existing ones. This means that most of the "2.0" basics are still valid in "3.5". Some "basic" functionalities are nevertheless augmented or changed in new versions. We will try to keep track of those as side notes where possible.
![]() | Wikipedia has related information atProgramming paradigm |
Keeping things very (too much?) simple we can say that a programming paradigm is a "style" of programming, a specific way to model problems and "translate" their solution in code.
From a developer point of view the .NET framework (and its class libraries) is a general-purpose object-oriented platform that is constantly extended to support other programming paradigms (generic programming with Generics, Aspect programming with attributes, Reactive programming with WF, Functional programming with Lambda expressions in C# 3.0, etc.). That "extension process" mirrors that of Java. The .NET and Java platforms are the only two that currently support such extensive multi-paradigms extension process.
Discussing the extent and "theoretical soundness" of each of those paradigm implementations is obviously out of scope for this book.
Our point here is that navigating through all those programming styles in the same platform can get kind of confusing. Maintaining code is also getting more and more difficult because two original programmers could have solved the same problem using widely different "styles" or constructs.
We will thus try to connect, where possible, the different .NET concepts with their respective "style" to give the reader some context.
![]() | Wikipedia has related information atComponent-based software engineering |
![]() | Wikipedia has related information atComponent object model |
According toMSDN assemblies are: "the building blocks of .NET Framework applications; they form the fundamental unit of deployment, version control, reuse, activation scoping, and security permissions".
The .NET Framework is now Microsoft's preferred way of developing applications on the Windows platform. In that respect it succeeds the Component Object Model (COM). This is important to mention because despite some deployment and management problems (remember DLL Hell?) COM played an important role in the development of component-based computing (reusing whole executable components, not only program code). Major efforts have been invested to transfer the component-based concepts of COM to the .NET framework and a significant part of this book deals with those (security, installation, versioning, etc.).
The assembly is the successor of the COM component.
![]() | To do: |
Exam objective:Developing applications that use system types and collections.
![]() | Wikipedia has related information atComputer program |
![]() | Wikipedia has related information atObject oriented programming |
.NET is essentially a set of tools to build and execute computer programs. A computer program is a set of instructions given to a computer that executes those instructions automatically to manipulate some data. .NET follows the object-oriented paradigm which means that the instructions and data are grouped around ‘’objects’’ that represent things or concepts. Objects that share the same instructions and manipulate the same kind of data are grouped into the same type.
An object-oriented program is the definition of a series of types. For each type the kind of data and the instructions are specified. The instructions are grouped inside methods. One of the available instructions is the creation of an object of a defined type. Another kind of instruction is the request to execute a method associated with an object. This is called invoking a method. When a method is invoked its instructions are executed until the method terminates (returns). When the method returns the calling (invoking) method executes its next instruction (statement).
When you start the execution of a program the system creates a first object and invokes a method of that object (this is called themain method). Inside that method other objects are typically created and methods of those objects are invoked. Those methods will invoke other methods and create other objects and so on. Gradually the called methods will return and the '’main’’ method will eventually finish, marking the end of the program execution.
![]() |
![]() | Wikipedia has related information attype system |
This section will be obvious for experienced object oriented developers but some of the specific objectives of the exam are directly related to the type system.
Types are a way to classify the concepts or objects of a language. The way this classification is organized is called a 'type system'. The types themselves can also be categorized in different ways by the type system.
The first way to categorize types in .NET is to make a difference between types that are part of the framework class libraries (System types) and types that will be constructed by the developer (custom types).
Writing object oriented programs can be seen as the process of defining one or more custom types. Those types are then packaged in some kind of execution unit (Assemblies in the case of .NET). The assemblies are compiled and then executed starting at some entry point that will be a specified method of one of the custom type.
Those custom types use:
System types are also packaged in assemblies. The custom assemblies must reference the system assemblies in order to use the System types.
There are other ways to categorize types in .NET. One of them is by the way the objects created based on those types are mapped to the computer memory. This will give us Value types and Reference types.
Another way is by Reflection category (Class, Value types, Interfaces, Generics, etc.).
Yet another way is to distinguish the types that are directly supported by the runtime (built-in types) from those defined either in the class libraries or custom.
Those categories can also be intersected with one another, that will give us such things as "Built-in value types" or "System interfaces". Stay alert of the categorizations used when you encounter such combinations.
Namespaces are a way to organize types so that they can be more easily found. Seethis for a discussion on namespaces.
In the context of namespaces the System types are the types included in the System namespace or one of its sub-namespace and Custom types (non system types) should use other namespaces.
For a peek at how Microsoft describes the .NET type system seeMSDN. And then for an overview of the class libraries (System types) seeMSDN.
Most of the exam is in fact based on how to use the common parts of the type libraries (System types). This is why the list of exam objectives (and this book TOC) is so long.
For the newcomers to .NET, you may want to take a little break from the concepts here and make sure that you see how the concepts discussed so far are used in a very simple example. The next concepts are not that trivial. We will put such an examplehere.
![]() | Wikipedia has related information atCall stack |
Value types represent one part of the Value / Reference classification of the type system.
An instance of a value type directly contains its data (value). For example an Int32 local variable has its memory allocated directly on the stack.
The value types are themselves split in 3 categories:
Remember that built-in types are the types directly supported by the runtime.
They are the building blocks of any program because they are what the machine instructions ultimately act upon. The rest are essentially compositions of those types.
All of the built-in types are value types except for Object and String.
The built-in value types consist of
All built-in value types are defined in the System namespace (ex. System.Int32) and have keywords that represent them in the VB and C# (ex. int in C#, integer in VB.NET) except for InPtr and UInPtr.
We noted above that type classification can be quite confusing sometimes. As an example note that System.DateTime is presented as a built-in value type in theTraining kit (page 5) and this is not identified as an error in MSDN KB. It isnot a built-in type according to theofficial specification (page 19). The confusion comes from the fact that theTraining kit does not make a clear difference between System types (in the class libraries) and Build-in types (basic types dealt with directly by the runtime).
The point here is not to be fussy or depreciate the work done by the authors of the training kit. We just want to note that it may be worth to take a few minutes to clearly separate the concepts before heading to the code.
All value types derive from System.ValueType either directly for built-in and user-defined or indirectly through System.Enum for enumerations.
Enumerations are a way to name a set of values of an underlying integer type (signed or unsigned). As restrictions of an integer type they act as their underlying type.
User-defined value types and Enumerations both include System types and Custom types.
An example of a System user-defined value-type would be System.Drawing.Point used in drawing.
You build custom value types using specific language constructs (struct in C#, Structure in VB.NET).
An example of a System enumeration would be the System.Data.CommandType enumeration that specifies if a table is a text command, a call to a stored procedure, etc.
You build custom enumerations using specific language constructs (enum in C#, Enum in VB.NET).
For examples and notes on using value types see thissection. See also examples ofbuilding andusing user-defined value types.
![]() | Wikipedia has related information atDynamic memory allocation |
Reference types represent the other part of the Value / Reference classification of the type system.
Contrary to value types, an instance of a reference type does not directly contain its data (value), but instead contains some kind of a reference to the memory location of that value. For example a String local variable has memory allocated on the stack for a reference to the contained string, not the string itself. In that case the string itself will be allocated on the heap and garbage collected (more on that later).
Two built-in types are considered reference types: Object and String and they are also directly referenced in the System libraries (ex. System.String) and have their own constructs in the .NET languages (ex. string in C#).
The reference types are themselves split in four categories:
We will not talk about pointers in this book because no exam objective references them.
The next three sections will present arrays, classes and interfaces.
For a comparison of value / reference types trythis.
For other notes and an example of using reference types seethis.
![]() |
An array is essentially a group of objects, usually of the same type, than can be accessed via an index.
For a general discussion of arrays you can see the Wikipedia article (on the right) or go to the Wikibook ondata structures.
Arrays once were one of the most used features of programming languages because you can go from one item in the array to the next in a very efficient way (you can seeC pointers and arrays if you want more details on this). Today the availability of much more “computer power” has moved the focus from arrays to collections. The two main problems of arrays are:
Collections address most of the shortcomings of arrays (at a cost though). Arrays can still be considered for a fixed group of objects that have to be efficiently manipulated.
We will have some examples in theusing arrays section.
![]() | Wikipedia has related information atObject oriented programming |
![]() | Wikipedia has related information atClass (computer_science) |
Classes are themselves split in three:
Boxed value types will be discussed a little later in theboxing / unboxing section.
Delegates will also be covered later in theirsection.
User-defined classes are the basic realizations of the object oriented concepts.
Obviously a lot can be said about classes but since no exam objective reference to them we will assume that the reader is already familiar with the concept and have already worked with them (in .NET or elsewhere).
You can have System classes (hundreds and hundreds of them) and custom classes (where you will code the essential of your program logic).
We have examples ofusing andbuilding classes.
![]() | Wikipedia has related information atType polymorphism |
![]() | Wikipedia has related information atInterface (computer_science) |
If you want to get really confused on what exactly is object-oriented programming just check the Wikipedia article on Polymorphism :-).
The idea is just to be able to have a single type of reference to the "common part" of different types that have "something in common".
Rectangles and Ellipses are both "Shapes" so how can we get part of a program to manipulate "Shapes" without knowing about the specific of Rectangles or Ellipses. In such a situation we say that Shapes are polymorphic (literally they can take many forms).
In object-oriented programming you get this behavior with inheritance. A reference to a parent class (Shape) will manipulate child objects (Rectangles or Ellipses) without problems.
Interfaces were developed to get the same behavior in the context of component-based computing where you don't have access to the source code so you cannot use inheritance. The interface construct was the basis of all component communication in COM.
An interface is a contract to implement a set of methods in a clearly defined manner (method signatures). If you know that a class implements an interface you know that you can use any of the defined methods.
From that definition it is easy to imagine having a reference to an "interface instance" from which you can call any of the interface methods. So easy in fact that the framework provides just that.
Now suppose that instead of a Shape being a parent of Rectangle we just have a Shape interface that is implemented both by Rectangle and Ellipse. If I have a reference to a Rectangle object, I will be able to "cast" it to a reference to a Shape interface and pass it to the part of the program that knows only about "Shape objects".
This is exactly the same polymorphic behavior that we had via inheritance.
The class libraries rely heavily on interfaces and a clear understanding of the concept is essential.
An interesting problem with interfaces compared with inheritance is that youdo not get a default implementation (virtual parent methods) so you have to recode everything. The techniques and tools do exist here but there is always some extra work to do. More on that with generics...
We have examples ofusing andbuilding interfaces. Some interfaces of the System namespace are shown in thestandard interfaces section.
![]() | Wikipedia has related information atAspect-oriented programming |
We now take a short break of our discussions on types to talk a little bit about attributes. First of all attributes are not types. They are elements of information that are added to a program element (assemblies, classes, method, etc.) to qualify it outside of the normal code associated with that element.
Those added "attributes" serves at doing manipulations of the underlying program element without having to modify the execution logic of the element.
Why would we ever want to manipulate program elements outside execution code? The short answer here is that object oriented concepts do not easily deal with what is known as cross-cutting concerns, or aspects of a program that apply to all or most classes. Examples of such aspects are security, persistence, serialization, etc. Instead of modifying every class to add serialization logic (which has nothing to do with business rules) you can add serialization attributes to the class to direct the serialization process of those classes without changing the business logic (execution code).
A number of functionality of the framework rely on attributes to add information to program elements. The attributes are kept by the compilation process and associated with their qualifying element in the assemblies. They are analyzed programmatically at run time using reflection to adjust the behavior of "cross-cutting" functionalities.
As for types we have System attributes (part of the framework) and Custom attributes (built by the developer). The development of Customs attributes will be treated in thereflection section. Until then we will limit ourselves with System attributes and focus on defining them and knowing how they will determine the behavior of framework.
Theattributes usage section will give some example of how simple System attributes can be used.
Let's note here that attributes are not the only way to add "non-execution" information to a program to modify its behavior. XML configuration files for example can be used to specify parameters that will affect program execution. We will talk about those in the Configuration section of this book.
SeeMSDN for the discussion of attributes in C#.
![]() | Wikipedia has related information atCollection (computing) |
A collection is a grouping of objects. The framework has many types of collections that cover most of the situations where you would process objects as a group. Knowing these collection types will save you the time to "re-code" equivalent logic and will keep your program more maintainable.
Unlike arrays collections come in many flavors each with its specific internal organization. Each type of collection is related to a specific type of problem. We will point out the types of problems when we give examples of each type of collections.
We have two sections with collections examples:
The major drawback of collections is that in "real life" objects that are grouped together usually have some characteristics in common (they are the same type, have a common parent type or support a common interface). So most of the time we know "more" about the objects than merely their organization. Collections do not allow us to use that knowledge to validate the objects passed to the collection or code logic applicable to all objects of the collection (without casting and exception handling that is).
Generic collections where introduced in version 2.0 of the framework. They solve this problem while keeping the other advantages of collections. For that reason they should be used whenever possible instead of "plain" collections.
Some external links on collections areGotDotNet andAspNetResources
SeeMSDN for a general discussion on arrays, collections and data structures.
![]() | Wikipedia has related information atGeneric programming |
Generic programming or the use of parameterized types is not an object oriented concept. In that sense Generics are a bit like attributes, they were added to main stream object-oriented platforms to take care of situations that are not easily covered by object-oriented techniques.
To start our discussion please read the following interestinglinked article (annexes) that introduces the concept of generics in the context of generic collections. This externaltutorial does the same.
The concept of Generics is interesting because it applies the concept of generalization to types. Types themselves are generalizations of objects (the basis of object-oriented programming). So here we start manipulating types, namely having types as parameters.
The actual type will be obtained when you substitute the parameter type with a specific type (For example when you declare a variable of that type).
// C#List<int> myIntList = new List<int>()'// VB.NETDim myIntList As New List(Of Integer)
In the .NET framework this substitution is done during the second compilation (the just-in-time compilation from CIL to machine code). Said differently, generics are supported by the CIL and are thus part of the framework itself, not of the language used (ex. C#).
For more coverage on generics seeMSDN.
We have examples ofusing andbuilding generic types.
For examples of generics collections see theusing generic collections section.
![]() | Wikipedia has related information atExceptions |
This is how you throw a general exception:
// C#throw new Exception("This is an exception.");'// VB.NETThrow New Exception("This is an exception.")
This is how you handle an exception:
// C#try{ throw new Exception("This is an exception.");}catch (Exception e){ Console.WriteLine(e.Message);}'// VB.NETTry Throw New Exception("This is an exception.")Catch ex As Exception Console.WriteLine(ex.Message)End Try
![]() | Wikipedia has related information atDelegate (.NET) |
![]() | Wikipedia has related information atDelegation (programming) |
![]() | Wikipedia has related information atEvent-driven programming |
![]() | Wikipedia has related information atPublish/subscribe |
For the “official” discussion of events and delegates seeMSDN. What we will do here is a little more general discussion of the many concepts involved.
The first concept is delegation or the idea that part of the functionality of a class can be done “elsewhere” in the program, it can be delegated. The important benefit of delegation is that the “delegating” object does not have to know how the delegated functionality is actually implemented. One way to “delegate” is to define an interface. If an object has a reference to an interface it can delegate part of its functionality to the object implementing that interface without knowing much about that object.
.NET 2.0 defines another reference type called a delegate that implements the delegation pattern in a slightly different way. A delegate is a type that defines a reference to a single function that must have the same signature as the delegate definition. A signature is a description of the type of the function parameters and its return type. Like a class you can create an object of that type. The object created is a reference to a function that can be assigned (set the reference to a specific function), be passed as parameter or executed (the function that is referenced is actually executed). Unlike an interface, a delegate defines only one function and a delegate instance can be created directly (no need to have another class implementing the interface).
Most delegates in .NET derive from a multicast delegate. A multicast delegate is a delegate that keeps a list of references to functions having the same signature as the delegate definition instead of a single reference. You can add a reference to a multicast delegate using the += operator. When you execute a multicast delegate each function referenced is executed in turn.
If an object is from a class that implements a multicast delegate member, then if you have a reference to that object you can "add" to the multicast delegate a reference to a function of your choice. If the object decides to "execute" its delegate member then the function from which you added a reference will be executed.
This multicast delegate member is precisely what an event is in .NET. This is why events and delegates are almost always discussed together.
The procedure to define an event is:
Most of the time you will add a reference to one of your own method. When the referenced object fires its event it actually executes one of your methods without knowing it. This setup is an implementation of the publish / subscribe pattern. You subscribe to an event, signaling that you want to be informed when a specific "event" happens. Many object can subscribe to the same event. When the referenced object fires its event it "publishes" a message that the event has effectively happened in the form of a function call to all the "registered" functions.
So any class can define events. Many system classes define events to communicate to your code the fact that "something" happened in the executing environment (the mouse moved, a key was pressed, a message was received on a socket, etc.). Constructing a program that "waits" for events to happen and then react to them is called event programming. Most online applications and services follow this design. We will discuss in more details the way system events are catched in the section on multithreading.
For examples of events and delegates seethis section.
usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceHelloWorldLab1{classProgram{staticvoidMain(string[]args){Console.WriteLine("Hello world!");Console.WriteLine("Press ENTER to exit");Console.ReadLine();}}}
Note: when you create a new console project in Visual studio, all the code is generated by default except for the 3 "Console" lines in the Main method. Just add those 3 lines and run the program.
We have discussed all the parts of that program except for the role of the Console which will be discussed in the input/output section (Stream). For now, lets say that it is a System class, in the System namespace (the "using System" instruction makes the "System." part of "System.Console.Writeline()" optional) and that the WriteLine() and ReadLine() methods write and read strings to and from the console.
Exam objective:Manage data in a .NET Framework application by using the .NET Framework 2.0 system types.
(Refer System namespace)
Following are some "usage" oriented remarks about value types.
Value types contain the values they are assigned:
int a = 1;
Value types can also be created by using thenew keyword. Using thenew keyword initializes the variable with the default value obtained from the type's default constructor:
int a = new int(); return a;
Value types can be declared without being initialized, but they must be initialized to some value before being used:
int a; return a;
Value types cannot equalnull. .NET 2.0 provides aNullable type to get around this limitation, which is discussed inthe next section, butnull is not a valid value for value types:
int a = null;
If you copy a Value type to another Value type, the value iscopied. Changing the value of the copy has no effect on the value of the original. The second is merely a copy of the first - they are in no way connected after assignment. This is fairly intuitive:
int var1 = 1;int var2 = var1; var2 = 25; Console.WriteLine("The value of var1 is {0}, the value of var2 is {1}", var1, var2);
Which would result in the output:
The value of var1 is 1, the value of var2 is 25
Changing the value of the copy (var2 in this instance) had no effect on the value of the original (var1).This is different from reference types which copy a reference to the value, not the value itself.
Value types cannot be derived from.
Value types as method parameters are passed by value by default. A copy of the value-type is made and the copy is passed to the method as a parameter. If the parameter is changed inside the method it will not affect the value of the original value type.
![]() | To do: |
SeeMSDN
A nullable type...
System.Nullable<int> MyNullableInt; int? MyNullableInt;
bool? MyBoolNullable;
Be careful withnullable booleans! Inif, for, while or logical evaluation statements a nullable boolean will equate anull value withfalse—it willnot throw an error.
Methods:T GetValueOrDefault() &T GetValueOrDefault(T defaultValue)
Returns the stored value or the default value if the stored value is set tonull.
Properties:HasValue &Value
Nullable types have tworead only properties:HasValue andValue.
HasValue is a boolean property that returns true if Value !=null. It provides a means to check your type for a non-null value before using it where you might throw an error:
int? MyInt = null; int MyOtherInt; MyOtherInt = MyInt.Value + 1; if (MyInt.HasValue) MyOtherInt = MyInt.Value + 1;
Value returns the value of your type,null or otherwise.
int? MyInt = 27;if (MyInt.HasValue) return MyInt.Value; MyInt = null;return MyInt;
Wrapping / Unwrapping
Wrapping is the process of packaging a valuem from a non-nullable typeN to a nullable typeN? via the expressionnew N?(m)
Unwrapping is the process ofevaluating a nullable typeN? for instance m as typeN or NULL and is performed via the 'Value' property (e.g.m.Value).
Note: Unwrapping a null instance generates the exceptionSystem.InvalidOperationException
The ?? Operator (aka theNull Coalescing Operator)
While not for use solely with Nullable types, the?? operator proves very useful when you want to use a default value instead of anull value. The?? operator returns the left operand of a statement if not null, otherwise it returns the right operand.
int? MyInt = null;return MyInt ?? 27;
For more information see theblog entry by R. Aaron Zupancic on the ?? Operator
Building a value type must be very simple. The following example defines a custom "point" structure with only 2 double members. Seeboxing and unboxing for a discussion of implicit conversion of value types to reference types.
Building and using a custom value type (struct)
using System; using System.Collections.Generic; using System.Text; // namespace ValueTypeLab01 { class Program { static void Main(string[] args) { MyPoint p; p.x = 3.2; p.y = 14.1; Console.WriteLine("Distance from origin: " + Program.Distance(p)); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // method where MyPoint is passed by value public static double Distance(MyPoint p) { return Math.Sqrt(p.x * p.x + p.y * p.y); } } // MyPoint is a struct (custom value type) representing a point public struct MyPoint { public double x; public double y; } }
The above example can be used here. Note that the p variable does not have to be initialized with thenew operator.
The following sample shows simple uses of the System enumeration DayOfWeek. The code is much simpler to read than testing for an integer value representing a day. Note that using ToString() on an enum variable will give the string representation of the value (ex. “Monday” instead of “1”).
The possible values can be listed using Reflection. See that section for details.
For a discussion of the Enum class seeMSDN
There is a special type of enumeration called a flags enumeration. The exam objectives do not mention it specifically. SeeMSDN if you are interested.
Simple use of enumerations
using System; using System.Collections.Generic; using System.Text; // namespace EnumLab01 { class Program { static void Main(string[] args) { DayOfWeek day = DayOfWeek.Friday; if (day == DayOfWeek.Friday) { Console.WriteLine("Day: {0}", day); } DayOfWeek day2 = DayOfWeek.Monday; if (day2 < day) { Console.WriteLine("Smaller than Friday"); } switch (day) { case DayOfWeek.Monday: Console.WriteLine("Monday processing"); break; default: Console.WriteLine("Default processing"); break; } int i = (int)DayOfWeek.Sunday; Console.WriteLine("Int value of day: {0}", i); // Finishing Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } }
Building a custom enumeration is pretty straightforward as shown by the following example.
Declaring a simple enumeration
using System; using System.Collections.Generic; using System.Text; // namespace EnumLab02 { class Program { public enum MyColor { None = 0, Red, Green, Blue } static void Main(string[] args) { MyColor col = MyColor.Green; Console.WriteLine("Color: {0}", col); // Finishing Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } }
Reference types are more commonly referred to asobjects.Classes,Interfaces andDelegates are all reference types, as well as the built-in reference typesSystem.Object andSystem.String. Reference types are stored in managed Heap memory.
Unlike Value types, reference types can be assigned the valuenull.
Copying a reference type copies areference that points to the object, not a copy of the object itself. This can seem counter-intuitive at times, since changing a copy of a reference will also change the original.
A Value type stores the value it is assigned, plain and simple - but a Reference type stores apointer to a location in memory (on the heap). Think of the heap as a bunch of lockers and the Reference type holds the locker number (there are no locks in this metaphor). Copying a Reference type is like giving someone a copy of your locker number, rather than a copy of its contents. Two Reference types that point to the same memory is like two people sharing the same locker - both can modify its content:
Example of using Reference types
public class Dog{ private string breed; public string Breed { get {return breed;} set {breed = value;} } private int age; public int Age { get {return age;} set {age = value;} } public override string ToString() { return String.Format("is a {0} that is {1} years old.", Breed, Age); } public Dog(string dogBreed, int dogAge) { this.breed = dogBreed; this.age = dogAge; }}public class Example(){ public static void Main() { Dog myDog = new Dog("Labrador", 1); Dog yourDog = new Dog("Doberman", 3); yourDog = myDog; yourDog.Breed = "Mutt"; myDog.Age = 13; Console.WriteLine("Your dog {0}\nMy dog {1}", yourDog.ToString(), myDog.ToString()); }}
Since the yourDog variable and the the myDog variable both point to the same memory store, the output of which would be:
Your dog is a Mutt that is 13 years old.My dog is a Mutt that is 13 years old.
As a practice for manipulating reference types you may want to work with theString and StringBuilder classes. We have put these with the text manipulation section but manipulating strings is a basic operation of almost all programs.
SeeMSDN for reference information.
The use of the four major categories of System Generic Types will mainly be demonstrated elsewhere in this book:
If you copy the next very simple example in Visual Studio and try to add something other than an int to the list the program will not compile. This demonstrates the strong typing capability of generics.
Very simple use of generic
using System; using System.Collections.Generic; namespace GenericsLab01 { class Program { static void Main(string[] args) { List<int> myIntList = new List<int>(); myIntList.Add(32); myIntList.Add(10); // Try to add something other than an int // ex. myIntList.Add(12.5); foreach (int i in myIntList) { Console.WriteLine("Item: " + i.ToString()); } Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } }
You can use List<string> instead of List<int> and you will get a list of strings for the same price (you are using the same List(T) class).
The programming of a custom generic collection was shown in thearticle mentioned in the topics discussion.
Here we have an example of a Generic Function. We use the trivial problem of swapping two references. Although very simple we still see the basic benefits of Generics:
Simple custom generic function
using System; using System.Collections.Generic; using System.Text; namespace GenericsLab03 { class Program { static void Main(string[] args) { Program pgm = new Program(); // Swap strings string str1 = "First string"; string str2 = "Second string"; pgm.swap<string>(ref str1, ref str2); Console.WriteLine(str1); Console.WriteLine(str2); // Swap integers int int1 = 1; int int2 = 2; pgm.swap<int>(ref int1, ref int2); Console.WriteLine(int1); Console.WriteLine(int2); // Finish with wait Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // Swapping references void swap<T>(ref T r1,ref T r2) { T r3 = r1; r1 = r2; r2 = r3; } } }
Next step is to present an example including a generic interface, a generic class that implements that generic interface and a class derived from that generic class. The sample also uses interface and derivation constraints.
This is another simple problem involving employees and suppliers which have nothing in common except that they can request payment to a "payment handler" (seevisitor pattern).
The problem is to know where to put the logic if you have specific processing to do for a certain kind of payment just for employees. There are myriads of ways to solve that problem but the use of generics make the following sample clean, explicit and strongly typed.
The other nice thing is that it has nothing to do with containers or collections where you will find almost all of generic samples.
Please note that the EmployeeCheckPayment<T> class derives from CheckPayment<T> giving astronger constraint on the type parameter T (must be employee not just implement IPaymentInfo). That gives us the to opportunity to have access (in its RequestPayment method) to all payment logic (from the base class) at the same time as all employee public interface (thru the sender method parameter) and that without having to do any cast.
Custom generic interface and class
using System; using System.Collections.Generic; using System.Text; namespace GennericLab04 { class Program { static void Main(string[] args) { // Pay supplier invoice CheckPayment<Supplier> checkS = new CheckPayment<Supplier>(); Supplier sup = new Supplier("Micro", "Paris", checkS); sup.InvoicePayment(); // Produce employee paycheck CheckPayment<Employee> checkE = new EmployeeCheckPayment<Employee>(); Employee emp = new Employee("Jacques", "Montreal", "bigboss", checkE); emp.PayTime(); // Wait to finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } // Anything that can receive a payment must implement IPaymentInfo public interface IPaymentInfo { string Name { get;} string Address { get;} } // All payment handlers must implement IPaymentHandler public interface IPaymentHandler<T> where T:IPaymentInfo { void RequestPayment(T sender, double amount); } // Suppliers can receive payments thru their payment handler (which is given by an object factory) public class Supplier : IPaymentInfo { string _name; string _address; IPaymentHandler<Supplier> _handler; public Supplier(string name, string address, IPaymentHandler<Supplier> handler) { _name = name; _address = address; _handler = handler; } public string Name { get { return _name; } } public string Address { get { return _address; } } public void InvoicePayment() { _handler.RequestPayment(this, 4321.45); } } // Employees can also receive payments thru their payment handler (which is given by an object factory) // even if they are totally distinct from Suppliers public class Employee : IPaymentInfo { string _name; string _address; string _boss; IPaymentHandler<Employee> _handler; public Employee(string name, string address, string boss, IPaymentHandler<Employee> handler) { _name = name; _address = address; _boss = boss; _handler = handler; } public string Name { get { return _name; } } public string Address { get { return _address; } } public string Boss { get { return _boss; } } public void PayTime() { _handler.RequestPayment(this, 1234.50); } } // Basic payment handler public class CheckPayment<T> : IPaymentHandler<T> where T:IPaymentInfo { public virtual void RequestPayment (T sender, double amount) { Console.WriteLine(sender.Name); } } // Payment Handler for employees with supplementary logic public class EmployeeCheckPayment<T> : CheckPayment<T> where T:Employee { public override void RequestPayment(T sender, double amount) { Console.WriteLine("Get authorization from boss before paying, boss is: " + sender.Boss); base.RequestPayment(sender, amount); } } }
Some links to MSDN:
SeeMSDN
All types derive directly or indirectly from System.Object (including value types by the way of System.ValueType). This allows the very convenient concept of a reference to "any" object but poses some technical concerns because value types are not "referenced". Comes boxing and unboxing.
Boxing and unboxing enable value types to be treated as objects. Boxing a value type packages it inside an instance of the Object reference type. This allows the value type to be stored on the garbage collected heap. Unboxing extracts the value type from the object. In this example, the integer variable i is boxed and assigned to object o:
int i = 123;object o = (object) i; // boxing
Please also note that it is not necessary to explicitly cast an integer to an object (as shown in the example above) to cause the integer to be boxed. Invoking any of its methods would also cause it to be boxed on the heap (because only the boxed form of the object has a pointer to a virtual method table):
int i=123;String s=i.toString(); //This call will cause boxing
There is also a third way in which a value type can be boxed. That happens when you pass a value type as a parameter to a function that expects an object.Let's say there is a function prototyped as:
void aFunction(object value)
Now let's say from some other part of your program you call this function like this:
int i=123;aFunction(i); //i is automatically boxed
This call would automatically cast the integer to an object, thus resulting in boxing.
The object o can then be unboxed and assigned to integer variable i:
o = 123;i = (int) o; // unboxing
Performance of boxing and unboxing
In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value type is boxed, an entirely new object must be allocated and constructed. To a lesser degree, the cast required for unboxing is also expensive computationally.
SeeMSDN
Exam objective:Manage a group of associated data in a .NET Framework application by using collections.
(Refer System.Collections namespace -MSDN)
seeMSDN
The ArrayList class is used for arrays whose size will dynamically increase as required. An ArrayList is not necessarily sorted.
using System;using System.Collections;
public class Demo {public static void Main() { ArrayList myArrayList = new ArrayList(); myArrayList.Add("Testing"); myArrayList.Add("1...2...3"); }}
Count - Gets the number of elements contained in the ICollection.IsSynchronized - Gets a value indicating whether access to the ICollection is synchronized (thread safe).SyncRoot - Gets an object that can be used to synchronize access to the ICollection.
CopyTo - Copies the elements of the ICollection to an Array, starting at a particular Array index.
IEnumerator sample
public class Person{ public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName;}
public class PeopleEnum : IEnumerator{ public Person[] _people; //Enumerators are positioned before the first element //until the first MoveNext() call. int position = -1; public PeopleEnum(Person[] list) { _people = list; } public bool MoveNext() { position++; return (position < _people.Length); } public void Reset() { position = -1; } public object Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } }}
public class People : IEnumerable{ private Person[] _people; public People(Person[] pArray) { _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _people[i] = pArray[i]; } } public IEnumerator GetEnumerator() { return new PeopleEnum(_people); }}
Write down a handler for Practicing the above code.
protected void lnkEnumerator_Click(object sender, EventArgs e) { Person[] peopleArray = new Person[] { new Person("Irfan", "Akhtar"), new Person("Hammad", "Anwar"), new Person("Majid", "Aalim") }; PeopleEnum Prson = new PeopleEnum(peopleArray);
while (Prson.MoveNext () ) { Person P = (Person)Prson.Current; Response.Write("First Name : " + P.firstName + ", Last Name : " + P.lastName); }
People peopleList = new People(peopleArray);foreach (Person p in peopleList) Response.Write("First Name : " + p.firstName + ", Last Name : " + p.lastName);
SeeMSDN
public class Colors : System.Collections.IEnumerable{string[] colors = { "Red", "Green", "Blue" };
public System.Collections.IEnumerator GetEnumerator() {for (int i = 0; i < colors.Length; i++) { yieldreturn colors[i]; } }}
foreach (int iin myList.NamedIterator()){ System.Console.WriteLine(i);}
public System.Collections.IEnumerator GetEnumerator(){ yieldreturn "Statement returned on iteration 1"; yieldreturn "Statement returned on iteration 2";}
yield break;
Hashtable class -MSDN
CollectionBase class and ReadOnlyCollectionBase class
DictionaryBase class and DictionaryEntry class
Comparer class -MSDN
Queue class -MSDN
SortedList class -MSDN
BitArray class -MSDN
Stack class -MSDN
<noinclide></noinclude>
Exam objective:Improve type safety and application performance in a .NET Framework application by using generic collections.
(Refer System.Collections.Generic namespaceMSDN)
Simple use IComparable<T> (C#)
using System; using System.Collections.Generic; using System.Text; namespace GenericsLab05 { class Program { static void Main(string[] args) { List<Point> lst = new List<Point>(); lst.Add(new Point(-2, -2)); lst.Add(new Point(1, 1)); lst.Add(new Point(2, 2)); // Sort uses IComparable of Point lst.Sort(); foreach (Point pt in lst) { Console.WriteLine(pt.ToString()); } // Wait to finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } // This is out custom version of a point public struct Point : IComparable<Point> { public double x; public double y; public Point(double px, double py) { x = px; y = py; } // Comparaison done based on distance from origin public int CompareTo(Point other) { return Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)).CompareTo (Math.Sqrt(Math.Pow(other.x, 2) + Math.Pow(other.y, 2))); } public override string ToString() { return "(" + x.ToString() + "," + y.ToString() + ")"; } } }
Custom Comparer<T> (C#)
using System; using System.Collections.Generic; using System.Text; namespace GenericsLab06 { class Program { static void Main(string[] args) { List<Point> lst = new List<Point>(); lst.Add(new Point(-2, -2)); lst.Add(new Point(1, 1)); lst.Add(new Point(2, 2)); // Sort uses IComparable of Point lst.Sort(new DistanceComparer()); foreach (Point pt in lst) { Console.WriteLine(pt.ToString()); } // Wait to finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } // This is out custom version of a point public struct Point { public double x; public double y; public Point(double px, double py) { x = px; y = py; } public override string ToString() { return "(" + x.ToString() + "," + y.ToString() + ")"; } } // Derive from base comparer class to implement IComparer<T> public class DistanceComparer : Comparer<Point> { public override int Compare(Point p1, Point p2) { return Math.Sqrt(Math.Pow(p1.x, 2) + Math.Pow(p1.y, 2)).CompareTo (Math.Sqrt(Math.Pow(p2.x, 2) + Math.Pow(p2.y, 2))); } } }
Exam objective:Manage data in a .NET Framework application by using specialized collections.
(Refer System.Collections.Specialized namespace)
CollectionsUtil class -MSDN
Exam objective:Implement .NET Framework interfaces to cause components to comply with standard contracts.
(Refer System namespace)
IComparable interface -MSDN
IDisposable interface -MSDN
IConvertible interface -MSDN
ICloneable interface -MSDN
INullableValue interface -MSDN
IEquatable interface -MSDN
IFormattable interface -MSDN
Exam objectives:Control interactions between .NET Framework application components by using events and delegates.
(Refer System namespace)
Delegate class -MSDN
//delegate declaration public delegate void AlarmEventHandler(object sender,EventArgs e);
Simple delegate
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab01 { // declare the delegate type public delegate int IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Assign the delegate IntOperDel deleg = pgm.Increment; // Executing the delegate int res = deleg(32); Console.WriteLine("First value: " + res.ToString()); // Second assign deleg = pgm.Decrement; // Second execution res = deleg(32); Console.WriteLine("First value: " + res.ToString()); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to the delegate public int Increment(int n) { return n + 1; } // Second function to be assigned to the delegate public int Decrement(int n) { return n - 1; } } }
Callback delegate
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab02 { // declare the delegate type public delegate int IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Assign the delegate IntOperDel deleg = pgm.Increment; // Calling a function that will execute de delegate // as part of its own logic pgm.ExecuteCallBack(deleg); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // Function to be assigned to a delegate public int Increment(int n) { return n + 1; } // Function called with a delegate as parameter public void ExecuteCallBack(IntOperDel deleg) { int res = deleg(32); Console.WriteLine("Result from executing the callback: " + res.ToString()); } } }
Delegate member
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab03 { // declare the delegate type public delegate void IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(int n) { int res = n + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(int n) { int res = n - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member of the delegate type public IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { this.delMember(32); } } }
Event member
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab04 { // declare the delegate type public delegate void IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(int n) { int res = n + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(int n) { int res = n - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(32); } } }
EventArgs class -MSDN
public delegate voidDelegateTypeName (object sender, EventArgs e)
Event with delegate that follows the calling convention
using System; using System.Collections.Generic; using System.Text; // namespace EventLab01 { // the class containing the event data passed to the event handler public class IntEventData : EventArgs { public int IntParm = 0; // constructor public IntEventData(int i) { IntParm = i; } } // the delegate type public delegate void IntOperDel(object sender, IntEventData e); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(object sender, IntEventData e) { int res = e.IntParm + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(object sender, IntEventData e) { int res = e.IntParm - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, new IntEventData(32)); } } }
EventHandler delegates -MSDN andMSDN
public event EventHandlerEventName
Event with EventHandler delegate
using System; using System.Collections.Generic; using System.Text; // namespace EventLab03 { // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to the event public void Increment(object sender, EventArgs e) { int res = 32 + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to the event public void Decrement(object sender, EventArgs e) { int res = 32 - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event EventHandler delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, null); } } }
public event EventHandler<T>EventName
Event utilizing EventHandler<T>
using System; using System.Collections.Generic; using System.Text; // namespace EventLab02 { // the class containing the event data passed to the event handler public class IntEventData : EventArgs { public int IntParm = 0; // constructor public IntEventData(int i) { IntParm = i; } } // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(object sender, IntEventData e) { int res = e.IntParm + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(object sender, IntEventData e) { int res = e.IntParm - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event EventHandler<IntEventData> delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, new IntEventData(32)); } } }
Exam objective:Implementing service processes, threading, and application domains in a .NET Framework application
![]() | Wikipedia has related information atWindows service |
The term service stands here for a Windows service. The basic definition of a Windows service is a long-running process that does not require a user interface. Why would you need a long-running process that does not require a user interface? Essentially two reasons:
The exam objectives concerning services are very basic and touch the first problems that you will encounter when dealing with them:
The more important and complicated design issues are not covered by this exam and will be treated by the enterprise development exam.
![]() | Wikipedia has related information atThread (computer science) |
![]() | To do: |
![]() | Wikipedia has related information atApplication Domain |
![]() | To do: |
Exam objective:Implement, install, and control a service
(Refer System.ServiceProcess namespace)
Inherit from ServiceBase class -MSDN
ServiceController class and ServiceControllerPermission class
ServiceInstaller and ServiceProcessInstaller class
ServiceChangeDescription structure and ServiceChangeReason enumeration
Exam objective:Develop multithreaded .NET Framework applications
(Refer System.Threading namespace)
Thread class -MSDN
ThreadPool class -MSDN
ThreadStart delegate, ParameterizedThreadStart delegate, and SynchronizationContext class
Thread t1 = new Thread (new ThreadStart(LengthyLogic));public void LengthyLogic (){ // Logic code}
Thread t1 = new Thread(new ParameterizedThreadStart(LengthyLogic));// Use the overload of the Start method that has a parameter of type Object.t1.Start(myData);static void LengthyLogic(object data){ // Logic code}
Timeout class, Timer class, TimerCallback delegate, WaitCallback delegate, WaitHandle class, and WaitOrTimerCallback delegate
ThreadExceptionEventArgs class and ThreadExceptionEventHanlder class
ThreadState enumeration and ThreadPriority enumeration
ReaderWriterLock class -MSDN
AutoResetEvent class and ManualResetEvent class
IAsyncResult interface and ICancelableAsyncResult interface
EventWaitHandle class, RegisterWaitHandle class, SendOrPostCallback delegate, and IOCompletionCallback delegate
Interlocked class, NativeOverlapped structure, and Overlapped class
ExecutionContext class, HostExecutionContext class, HostExecutionContext manager, and ContextCallback delegate
LockCookie structure, Monitor class, Mutex class, and Semaphore class MSDN]
Exam objective:Create a unit of isolation for common language runtime in a .NET Framework application by using application domains
(Refer System namespace)
SeeMSDN
An application domain is a division of a process into multiple parts. Applications running in different application domains are as isolated as they would be in different processes. So they cannot access memory in another application domain. However, if native code is run, it can gain unlimited access to the whole process, which includes other application domains.
Application domains are easier to maintain and are faster because it is easier to communicate between application domains than between processes. An application domain can hold multiple assemblies.
To create an application domain, you must at least supply a name for the new application domain:
AppDomain ad = AppDomain.CreateDomain("Name");
UseAppDomain.CurrentDomain to get the application domain the calling thread is using.
SeeMSDN
It is possible to execute an assembly by name usingAppDomain.ExecuteAssemblyByName:
AppDomain ad = AppDomain.CreateDomain("Name"); ad.ExecuteAssemblyByName("aname, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a9b8c7d6");
Or useAppDomain.ExecuteAssembly to supply a path to the assemby:
AppDomain ad = AppDomain.CreateDomain("Name"); ad.ExecuteAssembly(@"c:\path\to\file.exe");
SeeMSDN
It is not possible to unload assemblies from the default application domain. However if an assembly is loaded in a different application domain, you can unload the whole application domain which includes all assemblies in that application domain.
To unload an application domain, use the staticAppDomain.Unload function:
AppDomain ad = AppDomain.CreateDomain("Name"); AppDomain.Unload(ad);
SeeMSDN
The most likely reason to modify the application domain configuration, is to restrict certain permissions to limit the damage if an attacker exploits vulnerabilities in an assembly.
An example is to run an assembly in theInternet Zone. The Internet Zone has limited permissions. To do this create aZone Evidence and supply it as a parameter when creating the Application Domain:
object [] myEvidenceTypes = {new Zone (SecurityZone.Internet)}; Evidence myEvidence = new Evidence(myEvidenceTypes, null); AppDomain ad = AppDomain.CreateDomain("Name", myEvidence); // Pass the Evidence when creating the App. Domain ad.ExecuteAssembly(@"c:\path\to\file.exe");
It is also possible to execute only one assembly in an Application Domain with different permissions;
object [] myEvidenceTypes = {new Zone (SecurityZone.Internet)}; Evidence myEvidence = new Evidence(myEvidenceTypes, null); AppDomain ad = AppDomain.CreateDomain("Name"); ad.ExecuteAssembly(@"c:\path\to\file.exe", myEvidence); // Pass the Evidence in the ExecuteAssembly function
Except Evidence, you can also use the AppDomainSetup class to set other properties.
AppDomainSetup ads = new AppDomainSetup(); ads.ApplicationBase = @"c:\Test"; ads.DisallowCodeDownload = true; AppDomain ad = AppDomain.CreateDomain("Name", null, ads); // use null as second parameter for default Evidence
SeeMSDN
Use theSetupInformation property of an AppDomain to read the settings from that application domain;
AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation; Console.WriteLine(ads.ConfigurationFile); Console.WriteLine(ads.ApplicationName);
Exam objective:Embedding configuration, diagnostic, management, and installation features into a .NET Framework application
Configuration management is used here in a restricted sense. It refers to the adaptation of an application to a specific execution environment or user. This is usually done thru the use of configuration files that specify the run time parameters of the application. The typical example of such configuration information is the connection string used to locate and connect to the application database. The exam objectives are all related to the actual interaction of the application with its configuration files.
The management or the design of the configuration files themselves is a vast subject that is not touched by the exam objectives so we will not cover it in this study guide.
![]() |
MSDN's definition is "Windows event logs allow your applications and components to record information about important events. You can use these records to audit access to your system, troubleshoot problems, and re-create usage patterns"
For a general discussion seeMSDN
For specifics on the EventLog class and some cautions about its use seeMSDN
Windows Management Instrumentation -MSDN
![]() | Wikipedia has related information atWindows Management Instrumentation |
![]() | To do: |
Exam objective:Embed configuration management functionality into a .NET Framework application.
(Refer System.Configuration namespace)
Configuration class and ConfigurationManager class
ConfigurationSettings class, ConfigurationElement class, ConfigurationElementCollection class, and ConfigurationElementProperty class
Implement IConfigurationSectionHandler interface -MSDN
ConfigurationSection class, ConfigurationSectionCollection class, ConfigurationSectionGroup class, and ConfigurationSectionGroupCollection class
Implement ISettingsProviderService interface -MSDN
Implement IApplicationSettingsProvider interface -MSDN
ConfigurationValidationBase class -MSDN
Implement IConfigurationSystem interface -MSDN
Exam objective:Create a custom Microsoft Windows Installer for .NET Framework components by using the System.Configuration.Install namespace, and configure the .NET Framework applications by using configuration files, environment variables, and the .NET Framework Configuration tool (Mscorcfg.msc).
Installer class -MSDN
Configure which runtime version a .NET Framework application should use -MSDN
Configure where the runtime should search for an assembly -MSDN
Configure the location of an assembly and which version of the assembly to use -MSDN andMSDN
Direct the runtime to use the DEVPATH environment variable when searching for assemblies -MSDN
AssemblyInstaller class -MSDN
ComponentInstaller class -MSDN
Configure a .NET Framework application by using the .NET Framework Configuration tool (Mscorcfg.msc) -MSDN
ManagedInstaller class -MSDN
InstallContext class -MSDN
InstallerCollection class -MSDN
Implement IManagedInstaller interface -MSDN
InstallEventHandler delegate -MSDN
Configure concurrent garbage collection -MSDN
Register remote objects by using configuration files -MSDN
Exam objective:Manage an event log by using the System.Diagnostics namespace
EventLog class -MSDN
EventSourceCreationData class -MSDN
You create an EventLog by creating the first event source that writes to that log.
The two simplest way to do this are:
Note that there is no "EventSource" class in the System.Diagnostics namespace even though an object representing the source is created in the registry.
C# EventLog creation Example
using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; namespace EventLogLab1 { class Program { static void Main(string[] args) { try { EventLog log1 = new EventLog("EvtLab2Log"); log1.Source = "EvtLab2Source"; // Actual creation happens next log1.WriteEntry("Example message", EventLogEntryType.Information, 123, 1); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } } }
The recommended way, which does not seem to be covered on the Training Kit (so probably not on the exam) is to use the EventLogInstaller class during the installation of the application. For reference purposes seeMSDN
Exam objective:Manage system processes and monitor the performance of a .NET Framework application by using the diagnostics functionality of the .NET Framework 2.0.
(Refer System.Diagnostics namespace)
Get a list of all running processes.
Retrieve information about the current process -MSDN
Get a list of all modules loaded by a process
PerformanceCounter class, PerformanceCounterCategory, and CounterCreationData class
Start a process both by using and by not using command-line arguments
StackTrace class -MSDN
StackFrame class -MSDN
Exam objective:Debug and trace a .NET Framework application by using the System.Diagnostics namespace.
Debug class and Debugger class
Debug class example
using System; using System.Diagnostics; using System.IO; using System.Reflection; class Program { static void Main(string[] args) { Debug.WriteLine("This is (by default) printed in the Output window."); //remove default listener Debug.Listeners.RemoveAt(0); //add a listener that can write to the Console window Debug.Listeners.Add(new ConsoleTraceListener()); Debug.WriteLine("This is printed in the console window."); //add a default listener again Debug.Listeners.Add(new DefaultTraceListener()); Debug.WriteLine("This is printed in both the Output and the Console window."); //remove all listeners Debug.Listeners.Clear(); //add a listener that writes to a file Debug.Listeners.Add(new TextWriterTraceListener(File.Create("C:\\test.txt"))); Debug.WriteLine("This is only printed to the newly created file."); //here we need to flush the output buffer Debug.Flush(); //keep console window open in debug mode Console.ReadLine(); } }
Trace class -MSDN
CorrelationManager class -MSDN
TraceListener class -MSDN
TraceSource class -MSDN
TraceSwitch class -MSDN
XmlWriterTraceListener class -MSDN
DelimitedListTraceListener class -MSDN
EventlogTraceListener class -MSDN
Debugger attributes -MSDN
Exam objective:Embed management information and events into a .NET Framework application.
(Refer System.Management namespace -MSDN)
Retrieve a collection of Management objects by using the ManagementObjectSearcher class and its derived classes
WMI basic example
class Program { static void Main(string[] args) {//Print all management info in the WMI class Win32_ComputerSystem PrintManagementInfo("Win32_ComputerSystem");//wait for user input to keep console window up in debug mode Console.ReadLine(); } static void PrintManagementInfo(string WMIClassName) { ManagementObjectSearcher mos;//Get all managementobjects of the specified class mos = new ManagementObjectSearcher("SELECT * FROM " + WMIClassName); foreach (ManagementObject MOCollection in mos.Get()) { foreach (PropertyData p in MOCollection.Properties) {//Some properties are arrays, //in which case the code below only prints //the type of the array. //Add a check with IsArray() and a loop //to display the individual array values. Console.WriteLine("{0}: {1}", p.Name, p.Value); } } } }
ManagementObjectSearcher example
class Program { static void Main(string[] args) { // Console.WriteLine("Physical disks: "); PrintManagementInfoProperty("Win32_DiskDrive", "Name"); Console.WriteLine("*****************************"); // Console.WriteLine("Logical disks: "); PrintManagementInfoProperty("Win32_LogicalDisk", "Name"); Console.WriteLine("*****************************"); // Console.WriteLine("Network adapters: "); PrintManagementInfoProperty("Win32_NetworkAdapter", "Name"); Console.WriteLine("*****************************"); // Console.WriteLine("Processes: "); PrintManagementInfoProperty("Win32_Process", "Name"); Console.WriteLine("*****************************"); ////wait for user input to keep console window up in debug mode Console.ReadLine(); } static void PrintManagementInfoProperty(string WMIClassName, string WMIPropertyName) { ManagementObjectSearcher mos;//Get the specified property for all objects of the specified class mos = new ManagementObjectSearcher("SELECT " + WMIPropertyName + " FROM " + WMIClassName); foreach (ManagementObject mo in mos.Get()) { PropertyData p = mo.Properties[WMIPropertyName]; Console.WriteLine("{0}", p.Value); } } }
Enumarating services example
class Program { static void Main(string[] args) { Console.WriteLine("Running services: "); //form the query, providing a WMI class name and a condition SelectQuery query = new SelectQuery("Win32_Service", "State='Running'"); //find matching management objects ManagementObjectSearcher mos = new ManagementObjectSearcher(query); // foreach (ManagementObject mo in mos.Get()) { Console.WriteLine(mo.Properties["Name"].Value); } // //wait for user input to keep console window up in debug mode Console.ReadLine(); } }
ManagementQuery class -MSDN
EventQuery class -MSDN
Subscribe to management events by using the ManagementEventWatcher class -MSDN
Exam objective:Implementing serialization and input/output functionality in a .NET Framework application
![]() | Wikipedia has related information atserialization |
Wikipedia's definition for serialization is : "in the context of data storage and transmission, serialization is the process of saving an object onto a storage medium (such as a file, or a memory buffer) or to transmit it across a network connection link in binary form".
The problem that is addressed here is that an object is created by a running process and is thus bound to the lifetime of that process instance. If for whatever reason, and there can be many, you want to "transport" the object in the context of another process instance you've got a problem, that you solve by "saving" the state of you object in the original process and "restoring" it in the destination process. This "saving" part is called serialization and the "restoring" part is called deserialization.
An object is serializable if its class name is prefixed with the [Serializable] attribute.
One can use theBinaryFormatter class to serialize an object. To serialize, use the BinaryFormatter's Serialize() method which takes a stream and a serializable object as parameters. To deserialize, use the BinaryFormatter's Deserialize() method which takes a stream as a parameter and returns a object that can be cast back to the original object type. Remember to close streams after you use them by calling the stream's Close() method.
One can use theXmlSerializer class to serialize an object. To serialize, use the XmlSerializer's Serialize() method which takes a stream and a serializable object as parameters. To deserialize, use the XmlSerializer's Deserialize() method which takes a stream as a parameter and returns a object that can be cast back to the original object type. Remember to close streams after you use them by calling the stream's Close() method.
For an overview of XML and SOAP serialization seeMSDN
The ISerializable interface allows an object to control its own serialization and deserialization.
A formatter is used to serialize objects into streams.
For a general discussion on IsolatedStorage tasks seeMSDN
Exam objective:Serialize or deserialize an object or an object graph by using runtime serialization techniques.
(Refer System.Runtime.Serialization namespace)
IDeserializationCallback interface -MSDN
IFormatter interface and IFormatterConverter interface
ISerializable interface -MSDN
OnDeserializedAttribute class and OnDeserializingAttribute class
OnSerializedAttribute class and OnSerializingAttribute class
OptionalFieldAttribute class -MSDN
SerializationEntry structure -MSDN
SerializationInfo class -MSDN
ObjectManager class -MSDN
Formatter class -MSDN
FormatterConverter class -MSDN
FormatterServices class -MSDN
StreamingContext structure -MSDN
Exam objective:Control the serialization of an object into XML format by using the System.Xml.Serialization namespace.
XmlSerializer class -MSDN
Control serialization by using serialization attributes -MSDN
Implement XML Serialization interfaces to provide custom formatting for XML serialization -MSDN
Delegates and event handlers are provided by the System.Xml.Serialization namespace -MSDN
Exam objective:Implement custom serialization formatting by using the Serialization Formatter classes.
SoapFormatter class -MSDN
BinaryFormatter class -MSDN
Exam objective:Access files and folders by using the File System classes.
(Refer System.IO namespace)
File class and FileInfo class
Directory class and DirectoryInfo class
DriveInfo class and DriveType enumeration
FileSystemInfo class and FileSystemWatcher class
Example: FileSystemWatcher w = new FileSystemWatcher(); w.Filter = "*.txt"; w.Path = @"C:\Windows";
Path class -MSDN
ErrorEventArgs class and ErrorEventHandler delegate
RenamedEventArgs class and RenamedEventHandler delegate
Exam objective:Manage byte streams by using Stream classes.
(Refer System.IO namespace)
FileStream class -MSDN
Stream class -MSDN
MemoryStream class -MSDN
BufferedStream class -MSDN
Exam objective:Manage the .NET Framework application data by using Reader and Writer classes.
(Refer System.IO namespace)
StringReader class and StringWriter class -MSDN andMSDN
TextReader class and TextWriter class
StreamReader class and StreamWriter class -MSDN andMSDN
BinaryReader class and BinaryWriter class
Exam objective:Compress or decompress stream information in a .NET Framework application and improve the security of application data by using isolated storage.
(Refer System.IO.Compression namespace)
(Refer System.IO.IsolatedStorage namespace)
IsolatedStorageFile class -MSDN
IsolatedStorageFileStream class -MSDN
DeflateStream class -MSDN
GZipStream class -MSDN
Exam objective:Improving the security of the .NET Framework applications by using the .NET Framework 2.0 security features
![]() | Wikipedia has related information atCode access security |
Code access security, CAS, allows the control of various permissions granted to specific managed applications.MSDN
Permissions allow access to system resources. A permission set is a collection of permissions. A code group relates exactly one permission set to exactly one evidence type. Evidence is used to identify an assembly. Evidence types can include the application directory, cryptographic hash of the assembly, publisher's digital signature, site from which the assembly was downloaded, cryptographic strong name of the assembly, URL from which the assembly was downloaded, and the security zone in which the assembly is running. Security zones include the computer zone, local Intranet zone, Internet zone, trusted site, and untrusted sites. See the Internet options security tab in Internet Explorer to view various security zones. An assembly can be associated with multiple code groups. Permission sets can be associated with multiple code groups.
A security policy is a logical grouping of code groups and permission sets. An untrusted managed assembly must pass through four security policies: The Enterprise security policy, machine security policy, user security policy, and application domain security policy. Any one of these security policies can deny an untrusted managed assembly permissions.
Exam objective: Implement code access security to improve the security of a .NET Framework application.
(Refer System.Security namespace)
SecurityManager class -MSDN
CodeAccessPermission class -MSDN
Modify the Code Access security policy at the machine, user, and enterprise policy level by using the Code Access Security Policy tool (Caspol.exe) -MSDN
PermissionSet class, NamedPermissionSet class, and PermissionSetCollection class
Standard Security interfaces
Exam objective:Implement access control by using the System.Security.AccessControl classes.
DirectorySecurity class, FileSecurity class, FileSystemSecurity class, and RegistrySecurity class
AccessRule class -MSDN
AuthorizationRule class and AuthorizationRuleCollection class
CommonAce class, CommonAcl class, CompoundAce class, GenericAce class, and GenericAcl class
AuditRule class -MSDN
MutexSecurity class, ObjectSecurity class, and SemaphoreSecurity class
Exam objective:Implement a custom authentication scheme by using the System.Security.Authentication classes.
(Refer System.Security.Authentication namespace -MSDN)
For a reference on custom authentification schemes seeMSDN
Exam objective:Encrypt, decrypt, and hash data by using the System.Security.Cryptography classes.
(Refer System.Security.Cryptography namespace)
DES class and DESCryptoServiceProvider class
HashAlgorithm class -MSDN
DSA class and DSACryptoServiceProvider class
SHA1 class and SHA1CryptoServiceProvider class
TripleDES and TripleDESCryptoServiceProvider class
MD5 class and MD5CryptoServiceProvider class
RSA class and RSACryptoServiceProvider class
RandomNumberGenerator class -MSDN
CryptoStream class -MSDN
CryptoConfig class -MSDN
RC2 class and RC2CryptoServiceProvider class
AssymetricAlgorithm classMSDN
ProtectedData class and ProtectedMemory class
RijndaelManaged class and RijndaelManagedTransform class
CspParameters class -MSDN
CryptoAPITransform class -MSDN
Hash-based Message Authentication Code (HMAC) -MSDN
Exam objective:Control permissions for resources by using the System.Security.Permission classes.
(Refer System.Security.Permission namespace)
SecurityPermission class -MSDN
PrincipalPermission class -MSDN
FileIOPermission class -MSDN
StrongNameIdentityPermission class -MSDN
UIPermission class -MSDN
UrlIdentityPermission class -MSDN
PublisherIdentityPermission class -MSDN
GacIdentityPermission class -MSDN
FileDialogPermission class -MSDN
DataProtectionPermission class -MSDN
EnvironmentPermission class -MSDN
IUnrestrictedPermission interface -MSDN
RegistryPermission class -MSDN
IsolatedStorageFilePermission class -MSDN
KeyContainerPermission class -MSDN
ReflectionPermission class -MSDN
StorePermission class -MSDN
SiteIdentityPermission class -MSDN
ZoneIdentityPermission class -MSDN
Exam objective:Control code privileges by using System.Security.Policy classes.
(Refer System.Security.Policy namespace)
ApplicationSecurityInfo class and ApplicationSecurityManager class
ApplicationTrust class and ApplicationTrustCollection class
Evidence class and PermissionRequestEvidence class
CodeGroup class, FileCodeGroup class, FirstMatchCodeGroup class, NetCodeGroup class, and UnionCodeGroup class
Condition classes
PolicyLevel class and PolicyStatement class
IApplicationTrustManager interface, IMembershipCondition interface, and IIdentityPermissionFactory interface
Exam objective:Access and modify identity information by using the System.Security.Principal classes.
(Refer System.Security.Principal namespace)
GenericIdentity class and GenericPrincipal class
WindowsIdentity class and WindowsPrincipal class
NTAccount class and SecurityIdentifier class
IIdentity interface and IPrincipal interface
WindowsImpersonationContext class -MSDN
IdentityReference class and IdentityReferenceCollection class
Exam objective:Implementing interoperability, reflection, and mailing functionality in a .NET Framework application
![]() | Wikipedia has related information atReflection (computer science) |
The Wikipedia definition for reflection in computer science is: "The process by which a computer program can observe and modify its own structure and behavior. The programming paradigm driven by reflection is called reflective programming".
The concept is implemented extensively in .NET because a lot of information is maintained at the common intermediate language (CIL) level.
Among other things you can:
Exam objective:Expose COM components to the .NET Framework and .NET Framework components to COM
(Refer System.Runtime.InteropServices namespace)
Import a type library as an assembly -MSDN
Create COM types in managed code -MSDN
Compile an interop project -MSDN
Deploy an interop application -MSDN
Qualify the .NET Framework types for interoperation -MSDN
Apply Interop attributes, such as the ComVisibleAttribute class -MSDN
Package an assembly for COM -MSDN
Deploy an application for COM access -MSDN
Exam objective:Call unmanaged DLL functions in a .NET Framework application, and control the marshalling of data in a .NET Framework application.
(Refer System.Runtime.InteropServices namespace)
Platform Invoke -MSDN
Create a class to hold DLL functions -MSDN
Create prototypes in managed code -MSDN
Call a DLL function -MSDN
Call a DLL function in special cases, such as passing structures and implementing callback functions
Create a new Exception class and map it to an HRESULT -MSDN
Default marshaling behavior -MSDN
Marshal data with Platform Invoke -MSDN
Marshal data with COM Interop -MSDN
MarshalAsAttribute class and Marshal class
Exam objective:Implement reflection functionality in a .NET Framework application (refer System.Reflection namespace), and create metadata, Microsoft intermediate language (MSIL), and a PE file by using the System.Reflection.Emit namespace.
Building a custom attribute (annexes)
Assembly class -MSDN
Assembly attributes -MSDN
Info classes
Binder class and BindingFlags -MSDN
MethodBase class and MethodBody class
Builder classes
Exam objective:Send electronic mail to a Simple Mail Transfer Protocol (SMTP) server for delivery from a .NET Framework application.
(Refer System.Net.Mail namespace)
MailMessage class -MSDN
MailAddress class and MailAddressCollection class
SmtpClient class, SmtpPermission class, and SmtpPermissionAttribute class
Attachment class, AttachmentBase class, and AttachmentCollection class
SmtpException class, SmtpFailedReceipientException class, and SmtpFailedReceipientsException class
SendCompleteEventHandler delegate -MSDN
LinkedResource class and LinkedResourceCollection class
AlternateView class and AlternateViewCollection class
Exam objective:Implementing globalization, drawing, and text manipulation functionality in a .NET Framework application
Text manipulation, in the context of the exam objectives, covers 3 main subjects: string building, regular expressions and text encoding. We look at each in the following paragraphs.
Text manipulation starts with the representation of a string which is done via theString class. No specific exam objective mentions the String class but we added a section for it because you must understand some of its specific characteristics.
Next comes theStringBuilder class that serves for efficient construction.
![]() | Wikipedia has related information atRegular expressions |
TheRegex,Match andGroup classes together implement the regular expressions support in the .NET framework.
Regular expressions are a world by themselves and have been around for quite some time.
There is a wikibook onregular expressions which, among other things, point to thisTutorial.
Regular expressions support in .NET basically allows for:
(Refer System.Globalization namespace)
Exam objective:Access culture and region information in a .NET Framework application
CultureInfo class -MSDN
CultureTypes enumeration -MSDN
RegionInfo class -MSDN
DateTimeFormatInfo class -MSDN
NumberFormatInfo class -MSDN
NumberStyles enumeration -MSDN
CompareInfo class -MSDN
CompareOptions enumeration -MSDN
Exam objective:Build a custom culture class based on existing culture and region classes
CultureAndRegionInfoBuilder class -MSDN
CultureAndRegionModifier enumeration -MSDN
Exam objective:Enhance the user interface of a .NET Framework application by using the System.Drawing namespace.
Exam objective:Enhance the user interface of a .NET Framework application by using brushes, pens, colors, and fonts
Brush class -MSDN
Brushes class -MSDN
SystemBrushes class -MSDN
TextureBrush class -MSDN
Pen class -MSDN
Pens class -MSDN
SystemPens class -MSDN
SolidBrush class -MSDN
Color structure -MSDN
ColorConverter class -MSDN
ColorTranslator class -MSDN
SystemColors class -MSDN
StringFormat class -MSDN
Font class -MSDN
FontConverter class -MSDN
FontFamily class -MSDN
SystemFonts class -MSDN
Exam objective:Enhance the user interface of a .NET Framework application by using graphics, images, bitmaps, and icons
Graphics class -MSDN
BufferedGraphics class -MSDN
BufferedGraphicsManager class -MSDN
Image class -MSDN
ImageConverter class -MSDN
ImageAnimator class -MSDN
Bitmap class -MSDN
Icon class -MSDN
IconConverter class -MSDN
SystemIcons class -MSDN
Exam objective:Enhance the user interface of a .NET Framework application by using shapes and sizes
Point Structure -MSDN
PointConverter class -MSDN
Rectangle Structure -MSDN
RectangleConverter class -MSDN
Size Structure -MSDN
SizeConverter class -MSDN
Region class -MSDN
Exam objective:Enhance the text handling capabilities of a .NET Framework application, and search, modify, and control text in a .NET Framework application by using regular expressions
(Refer System.Text namespace)
(Refer System.RegularExpressions namespace)
The String class isnot a specific exam objective but was added to have a place to discuss some of its characteristics.
String class -MSDN
The StringBuilder class is used for very fast string concatenation. If you use conventional string concatenationthen it will run very slow because a string is held in an array. Each concatenation causes the array to increase its sizeand the memory has to be copied to a new location internally. This is very slow.
For fast string concatenations use StringBuilder instead. It is about 1000 times faster (depending on the stringyou concatenate).
StringBuilder class -MSDN
Refer to the example to measure the performance differences.
StringBuilder example
using System;using System.Collections;public class Demo{public static void Main() { const int len = 30; const int loops = 5000; // DateTime timeStart, timeStop; // // Measure time for normal string concatenation timeStart = DateTime.Now; string str = ""; for (int i = 0; i < loops; i++) { str += new String('x', len); } timeStop = DateTime.Now; int millis = timeStop.Subtract(timeStart).Milliseconds; Console.WriteLine("Duration for " + loops + " loops: " + millis + " ms"); // // Measure time for StringBuilder string concatenation StringBuilder sb = new StringBuilder(); timeStart = DateTime.Now; for (int i = 0; i < loops; i++) { sb.Append(new String('x', len)); } str = sb.ToString(); timeStop = DateTime.Now; millis = timeStop.Subtract(timeStart).Milliseconds; Console.WriteLine("Duration for " + loops + " loops: " + millis + " ms"); // Console.ReadLine(); }}
Regex class -MSDN
Match class -MSDN
MatchCollection class -MSDN
Group class -MSDN
GroupCollection class -MSDN
Encoding class -MSDN
EncodingInfo class -MSDN
ASCIIEncoding class -MSDN
UnicodeEncoding class -MSDN
UTF8Encoding class -MSDN
Encoding Fallback classes -MSDN
Decoder class -MSDN
Decoder Fallback classes -MSDN
Capture class -MSDN
CaptureCollection class -MSDN
![]() | Wikipedia has related information at.NET Framework |
.NET Framework Application Development Foundation Self-Paced Training Kit, Second EditionTony NorthrupMicrosoft Press
We reference that book as the "training kit" since it is recommended by Microsoft as a training aid for the 70-536 exam (for example seeMCPD).
If you use the training kit you might want to lookhere for a list of known corrections. Other potential corrections are listed in this wikibook.
Visual C#: The language - 2005 EditionDonis MarchallMicrosoft Press
Also recommended as a training aid for the 70-536 exam (for example seeMCPD)
If you want to go deeper into the definition of the common language infrastructure you can download theofficial specification
This is not required for the exam but we will use the specification a couple of times to clarify ambiguities in the MSDN documentation or other reference manuals.
The annexes are a series of articles on specific subjects that are referenced by the main text but were not integrated in it.
In order to understand Generics, we should first look why we would want to use them. This is best explained with a simple example. Let's say we want to create a collection of clients, this is something that we do often. We take a simple Client class that has a name and an account number. Often an ArrayList will be used to store multiple clients in memory like this:
/// <summary> /// Representation of a client /// </summary> public class Client { private string _name; private string _accountNumber; /// <summary> /// Gets or sets the account number. /// </summary> /// <value>The account number.</value> public string AccountNumber { get { return _accountNumber; } set { _accountNumber = value; } } /// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> public string Name { get { return _name; } set { _name = value; } } /// <summary> /// Initializes a new instance of the <see cref="T:Client"/> class. /// </summary> /// <param name="name">The name.</param> /// <param name="accountNumber">The account number.</param> public Client(string name, string accountNumber) { _name = name; _accountNumber = accountNumber; } /// <summary> /// The Main entry point of the console application /// </summary> /// <param name="args">The command line arguments</param> static void Main(string[] args) { ArrayList clients = new ArrayList(); clients.Add(new Client("Marco", "332-3355")); clients.Add(new Client("Martinus", "453-5662")); foreach (Client client in clients) { Console.WriteLine("The account {0} belongs to {1}", client.AccountNumber, client.Name); } Console.ReadLine(); } }
This probably looks familiar for most of the readers, but by using an ArrayList we are not type safe, which is in my opinion is bad. Also we need to cast (and uncast) the object when we want to do something cool with it. With value types there is an other issue, we constantly Box and unbox the objects in the list.
A better way store the clients would be to use typed collections, this will solve the problem with type safety and we don’t have to cast the retrieved object every time we use it. A good way to do this is by inheriting an object form the CollectionBase class and looks like this:
/// <summary> /// Representation of a client /// </summary> public class Client { private string _name; private string _accountNumber; /// <summary> /// Gets or sets the account number. /// </summary> /// <value>The account number.</value> public string AccountNumber { get { return _accountNumber; } set { _accountNumber = value; } } /// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> public string Name { get { return _name; } set { _name = value; } } /// <summary> /// Initializes a new instance of the <see cref="T:Client"/> class. /// </summary> /// <param name="name">The name.</param> /// <param name="accountNumber">The account number.</param> public Client(string name, string accountNumber) { _name = name; _accountNumber = accountNumber; } /// <summary> /// The Main entry point of the console application /// </summary> /// <param name="args">The command line arguments</param> static void Main(string[] args) { ClientList clients = new ClientList(); clients.Add(new Client("Marco", "332-3355")); clients.Add(new Client("Martinus", "453-5662")); foreach (Client client in clients) { Console.WriteLine("The account {0} belongs to {1}", client.AccountNumber, client.Name); } Console.ReadLine(); } } /// <summary> /// A list of clients /// </summary> public class ClientList : CollectionBase { /// <summary> /// Adds the specified client to the list. /// </summary> /// <param name="client">The client.</param> /// <returns></returns> public int Add(Client client) { return List.Add(client); } /// <summary> /// Gets or sets the <see cref="T:Client"/> at the specified index. /// </summary> /// <value></value> public Client this[int index] { get { return (Client)List[index]; } set { List[index] = value; } } }
This looks a lot better than when we where using the ArrayList in the first example and is in general a good way to go. But what if your application grows, and we get more types that we want to store in collections like an Account, or a bank. With the 1.1 framework we had to create a new collection class for every type of object that we used, or fall back to the ugly ArrayList method. However with the new 2.0 framework MS has added Generics. This makes it possible to create classes and methods that use type parameters. This allows developers to create classes and methods that defer the specifications of certain types until the class is defined and instantiated in the code. By using the generic type parameters developers can write classes that others can use without incurring the risks involved with un-typed classes like ArrayList and reduces the work developers have to do compared to creating typed collections. So lets look at how the code looks when we are using the Generic List<T> class from the framework.
/// <summary> /// Representation of a client /// </summary> public class Client { private string _name; private string _accountNumber; /// <summary> /// Gets or sets the account number. /// </summary> /// <value>The account number.</value> public string AccountNumber { get { return _accountNumber; } set { _accountNumber = value; } } /// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> public string Name { get { return _name; } set { _name = value; } } /// <summary> /// Initializes a new instance of the <see cref="T:Client"/> class. /// </summary> /// <param name="name">The name.</param> /// <param name="accountNumber">The account number.</param> public Client(string name, string accountNumber) { _name = name; _accountNumber = accountNumber; } /// <summary> /// The Main entry point of the console application /// </summary> /// <param name="args">The command line arguments</param> static void Main(string[] args) { List<Client> clients = new List<Client>(); clients.Add(new Client("Marco", "332-3355")); clients.Add(new Client("Martinus", "453-5662")); foreach (Client client in clients) { Console.WriteLine("The account {0} belongs to {1}", client.AccountNumber, client.Name); } Console.ReadLine(); } }
Thanks to Generics we have created a type-safe collection as easy as we would normally instantiate an ArrayList without writing our own typed collection.Now that we have had a brief look at how we can use Generics to reduce the amount of code we need to write, while still using typed collections let's see how we could create our custom Generic Class. To demonstrate this I have created an example Class which inherits from the DictionaryBase class. This implementation of the dictionary class will accept a GUID as the key and has a Type parameter as the value type. If you are a bit like me you will use GUIDS to identify your records in a database so using this as the key in a Typed collection was something I liked to do a lot. So now I’ve got a cool dictionary that I can use with all my objects I created when retrieving data from my database, and I will give you the code:
/// <summary> /// Representation of a client /// </summary> public class Client { private string _name; private string _accountNumber; /// <summary> /// Gets or sets the account number. /// </summary> /// <value>The account number.</value> public string AccountNumber { get { return _accountNumber; } set { _accountNumber = value; } } /// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> public string Name { get { return _name; } set { _name = value; } } /// <summary> /// Initializes a new instance of the <see cref="T:Client"/> class. /// </summary> /// <param name="name">The name.</param> /// <param name="accountNumber">The account number.</param> public Client(string name, string accountNumber) { _name = name; _accountNumber = accountNumber; } /// <summary> /// The Main entry point of the console application /// </summary> /// <param name="args">The command line arguments</param> static void Main(string[] args) { GuidDictionary<Client> clients = new GuidDictionary<Client>(); Guid clientID1 = Guid.NewGuid(); Guid clientID2 = Guid.NewGuid(); clients.Add(clientID1, new Client("Marco", "332-3355")); clients.Add(clientID2, new Client("Martinus", "453-5662")); Console.WriteLine("The account {0} belongs to {1}", clients[clientID1].AccountNumber, clients[clientID1].Name); Console.WriteLine("The account {0} belongs to {1}", clients[clientID2].AccountNumber, clients[clientID2].Name); Console.ReadLine(); } } public class GuidDictionary<T> : DictionaryBase { public void Add(Guid id, T item) { Dictionary.Add(id, item); } public T this[Guid id] { get { return (T)Dictionary[id]; } set { Dictionary[id] = value; } } }
Well it's probably not as wonderful as you expected, a lot of methods the standard dictionary has aren’t even implemented, but hey I have to leave some fun things to do for you the reader.
So what exactly did we do in the above code? We have created a Dictionary that is indexed by a Guid and uses a type parameter to limit our add method and our indexer. Now when we create a new instance of the class and specify the type parameter we have a type-safe dictionary which can be used to store and retrieve the type of objects by the given Guid.
The T in the declaration is only a name for the thing, we could as easily use the following: VeryLongNameForTheTypeParameter instead of T.Ok so we have seen how to use the type parameter to create a generic class. But before we move on to the next part lets look at the System.Collections.Generic.Dictionary<>. This class must be instantiated by providing 2 type parameters named TKey and TValue. This shows us that we can use more than one type parameter in our definition, and also shows that it was a waste of time to build my own dictionary class I could as easily used the generic dictionary like this: Dictionary<Guid, Client> and be over with it.
Original text for this page authored byWilliam "Scott" Baker
Attributes are a way to "tag" elements of your code's metadata with descriptive information that can be accessed at runtime using reflection. Attributes must derive fromSystem.Attribute, either directly or indirectly. A multitude of attributes exist in the .NET framework; you can also define your own. There are three aspects to using attributes in your code:
As previously mentioned, there are several predefined attributes in the .NET Framework; you may have already used them in your code. The XML parser in particular relies heavily on attributes when (de)serializing objects. You can also define your own custom attributes, as we will show here. Defining a custom attribute involves three steps:
(AttributeTargets.All, AllowMultiple = true, Inherited = false)]public Class QualityCheckAttribute :System.Attribute { }
Notice the use of "" vs. "AttributeUsageAttribute". By convention, all attributes are named with the "Attribute" suffix - but the suffix can be omitted when used in code. This holds true for user defined attributes as well; theQualityCheckAttribute attribute could be referenced as either:
[QualityCheckAttribute]
TheAttributeUsageAttribute has three members:ValidOn, AllowMultiple andInherited.
All (any element) Delegate GenericParameter ParameterAssembly Enum Interface PropertyClass Event Method ReturnValueConstructor Field Module* Struct*Module refers to a portable executable (.exe or.dll), and not a Visual Basic standard module.
You can also combine target types as a bitwise OR operation to specify multiple acceptable values:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[QualityCheck("Scott Baker", "02/28/06", IsApproved = true, Comment = "This code follows all established guidelines. Release approved.")][QualityCheck("Matt Kauffman", "01/15/06", IsApproved = false, Comment = "Code quality much improved. Minor revision required.")][QualityCheck("Joe Schmoe", 01/01/06", IsApproved = false, Comment = "This code is a mess and needs a complete rewrite")]public class MyClass{}
[AttributeUsage(AttributeTargets.Class)]public class AttrOneAttribute : Attribute{ }[AttributeUsage(AttributeTargets.Class, )]public class AttrTwoAttribute : Attribute{ }[AttrOne][AttrTwo]public class ClassOne { }public class ClassTwo : ClassOne{ }
public Class QualityCheckAttribute :System.Attribute { }public Class FinalCheck : QualityCheckAttribute {}
public Class QualityCheckAttribute : System.Attribute{ }
As previously mentioned, the use ofAttributeUsageAttribute is required in VB. In C#, it is automatically applied with the default values if not declared.
public class QualityCheckAttribute : Attribute{ public QualityCheckAttribute(string Name, string Date) }
public class QualityCheckAttribute : Attribute{ private string _name; private string _date; private bool isApproved; public QualityCheckAttribute(string Name, string Date) { }}
Keep in mind that a variable in your code can beboth a positional parameterand a named parameter. If we were to add public properties for the_name
and_date
fields we could use them either as named parameters or positional parameters. Of course, this is not a recommended practice: required parameters should be positional and optional parameters should be named.
You have already seen examples of assigning an attribute to a code member. However, there are some points that must be clarified.
public class MyAttribute : Attribute{ public string MyMethod(aString) { return aString; }}
Disambiguation resolves these issues. By specifying the code type the attribute is applied to, we are able to resolve the confusion. The code below shows that the attribute applies to thereturn value:
public class MyAttribute : Attribute{ [ : SomeAttribute] public string MyMethod(aString) { return aString; }}
The table below lists all declarations where attributes are allowed; for each declaration, the possible targets for attributes on the declaration are listed in the second column. Targets in bold are the defaults.
assemblyassemblymodulemoduleclasstypestructtypeinterfacetypeenumtypedelegatetype, returnmethodmethod, returnparameterparamfieldfieldproperty — indexerpropertyproperty — get accessormethod, returnproperty — set accessormethod, param, returnevent — fieldevent, field, methodevent — propertyevent, propertyevent — addmethod, paramevent — removemethod, param*Reference:Disambiguating Attribute Targets (C# Programming Guide)
One would think that theAttributeUsageAttribute's AttributeTargets in an attribute's definition would help to prevent this confusion: one would be wrong. The compiler does not use theAttributeUsageAttribute information when resolving conflicts. Even if you define an attribute to apply only to a specific type, for instanceAttributeTargets.Return, you must still clarify that it applies to thereturn type when applying the attribute or the compiler will use the default targetmethod type, and throw an error.
[AttrOne(...), AttrTwo(...)] [AttrOne(...)][AttrTwo(...)]
The two are equivalent. Keep in mind that if you are going to specify more than one attribute in a single brace, they must apply to the same target type. If not, you must give each type a separate declaration:
[return : AttrOne(...), method : AttrTwo(...)] [return : AttrOne(...)][method : AttrTwo(...)]
Being able to declare and apply attributes is not very helpful unless we can retrieve that data and do something with it. Fortunately, its a straightforward process. There are three basic scenarios that will be addressed:
To access attribute information:
The example code below declares a classExampleClass with aQualityCheck attribute. TheGetSingleAttribute method accepts a target member type and the type of attribute you're looking for. TheAttribute.GetCustomAttribute method retrieves the attribute information into theattr object, from which we can read the all-importantIsApproved property:
[QualityCheck("Scott Baker", "02/04/2006", IsApproved = false)]public class ExampleClass{ public static void Main() { GetSingleAttribute(typeof(ExampleClass), typeof(QualityCheck)) } public static void GetSingleAttribute(Type targetType, Type attrType) { typeof(attrType) attr = (attrType)Attribute.(targetType, typeof(attrType)); if (attr == null) { } else { Console.Writeline(attr.IsApproved); } }
An important factor to keep in mind is that theGetCustomAttribute method is designed to readone and only one attribute.GetCustomAttribute actually checks to see if more than one attribute matches - if there is no match it returnsnull, but if there is more than one match it will throw an . When checking for attributes the only time it is safe to useGetCustomAttribute is when the attribute's definition states[AttributeUsage(AllowMultiple=)].
Reading multiple instances of an attribute on a member isn't much different than reading one; to read multiple attributes use the pluralGetCustomAttributes, which returns an array of attributes. You can then iterate through the resultant array and read the values:
QualityCheck[] attrArray = (QualityCheck[])Attribute.GetCustomAttributes(t, typeof(QualityCheck));foreach (QualityCheck attr in attrArray){ Console.Writeline(attr.IsApproved);}
What if you want to do something a little more complex, like checking each method in a class for a QualityCheck attribute? Thanks to theSystem.Reflection namespace, we don't have to even break a sweat. Simply read all the members (methods, in this instance) into aMemberInfo array and iterate through them:
public class ExampleClass{ public static void Main() { RetrieveAttributes(typeof(ExampleClass)); } public void RetrieveAttributes(Type t) { MemberInfo[] methodList = t.GetMethods(); foreach (MemberInfo m in methodList) { QualityCheck[] attrArray = (QualityCheck[])Attribute.GetCustomAttributes(m, typeof(QualityCheck)); foreach (QualityCheck attr in attrArray) { Console.Writeline(attr.IsApproved); } } }}