.NET Development Foundation/AllInOne
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 use main page).
Preface
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 Microsoft certification 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 (see discussion page).
The preface contains information relevant to the context of the document, authors, wikibooks, etc. You can skip to the Introduction if you are primarily interested in the module content.
Audience and other Wikibooks resources
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:
- A description of NET 3.0 features
- An introduction to VB .NET
- A featured book on C#
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!
Contributions
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:
- Wikibooks are about textbooks not "standard" wikis. The project team is looking for continuous narratives that can be read from top to bottom. For somebody used to the MSDN type of documentation this can be a significant adjustment.
- Links only pages do not fit the above picture and are actively discouraged. If you create a page, be sure to have content to put on it :-)
- The administrators use templates to ask questions or notify of incomplete tasks. Those templates produce rather flashy notices that can be surprising at first. Don't worry about the look and ask for clarifications. The admins are very helpful and nice and will help you with whatever you may need.
- Code samples are very welcome and should be put in "hidden" sections to preserve the flow of the text. see example section. A sample should be kept as short as possible but the space limitations of printed material obviously do not apply here. We thus encourage you to have complete, yet clear and simple, programs so they can be directly tested and used.
- Use the discussion page for questions or comments.
- Use the official Actual4Exam's 70-536-CSHARP or 70-536-VB Simulation PrepKit for passing the 70-536 exam.
- Try uCertify's 70-536-CSHARP or 70-536-VB Simulation PrepKit for passing the 70-536 exam.
- Try qualitydumps 70-536 or examsdeal 70-536 Simulation exam questions for passing the 70-536 exam.
Exam information and certifications
Current information on the exam can be found at MSDN Exam Information
This module is the study guide for the first exam (70-536) for obtaining many Microsoft certifications:
- Microsoft Certified Technology Specialist: .NET Framework 2.0 Web Applications
- Microsoft Certified Technology Specialist: .NET Framework 2.0 Windows Applications
- Microsoft Certified Technology Specialist: .NET Framework 2.0 Distributed Applications
- Microsoft Certified Professional Developer: Web development
- Microsoft Certified Professional Developer: Windows development
- Microsoft Certified Professional Developer: Enterprise application development
Authors
William "Scott" Baker (User:Scott98390)
- If you contribute to this book, if you wish, please add your name here. The contributors for a specific article can be traced by its history.
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.
Introduction
Module objectives
This study guide does not aim at replacing the other resources that exist to get prepared to pass the 70-536 exam:
- we provide links to the MSDN library, we do not try to replace it. People who pass the exam often note that the training kit does not cover every aspect of the exam and that consulting the MSDN documentation is a big plus.
- we provide links to Wikipedia and other Wikimedia projects where applicable. This is not a series of theoretical or encyclopedia articles but a guide on how the concepts are implemented in the .NET framework and how to use them.
- we do not provide testing software
- we do not pretend that this module replaces the recommended training kit or any other recommended material from Microsoft.
What we do provide though, even at this document's grossly incomplete stage, is:
- an exhaustive list of the objectives of the exam as stated by Microsoft
- links from all exam objectives to the corresponding MSDN library article.
- "textbook like" explanations for a growing number of topics with links to related external sources.
- and most of all, a place to put your important notes and code examples for your revision before the exam and as a reference for your professional work afterward. No training kit or library provides that in a shared and controlled environment.
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.
Module structure
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:
- a first section covers the major concepts (topics) treated in that chapter. This "topics" section allows us to somewhat separate the "what" from the "how-to". Please note that the exam is heavily oriented toward the utilization of the libraries and tools and that an understanding of the concepts is highly insufficient as a preparation for the exam.
- a second section then details each of the second, third and fourth level exam objectives for that objective category (how-to's, detailed usage and references to MSDN library).
Eventually, we would like to have:
- a "revision questions" section for each chapter where we could discuss the kind of questions that could be asked at the exam.
- an "advanced" section where we could put the more advanced material and keep the text flow of the basic sections at a level that corresponds to the knowledge required for the exam.
As of December 7, 2007:
- 24 subjects are detailed on separate pages (the subject title is the link). Most of those will eventually be integrated into the main page for a better flow of the text.
- all of the subjects are directly linked to the Microsoft Software Developers Network (MSDN) library, about 480 directly from the main page (the "MSDN" following the title is the link) and the others from their respective subpage.
- we just started to link the "topics" sections to Wikipedia articles to give you a feel of how the concepts are defined and treated outside of Microsoft's world.
Some sections are relatively advanced and others are awaiting your contributions. The more advanced sections are not all at the beginning of the module.
The .NET Framework
In the certification paths where exam 70-536 "Microsoft .NET Framework 2.0 Application 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 on MSDN .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 on MSDN).
Wikipedia's definition points to the two more important aspects from a developer point of view:
- The presence of a huge set of class libraries that allows for all of the common programming tasks. Beside the sheer size of the those class libraries, they are also evolving at a rapid pace.
- The fact that the execution environment is specific to the framework. The term "virtual machine" is often used to qualify such an environment.
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.
Framework structure
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:
- The "source code" of the second compilation (the CIL code) is always available to the virtual machine at runtime. This means that this code can easily be analyzed at runtime, contrary to conventional compiled environment. This characteristic is the base for the reflection functionality of the platform. Not only can we analyze the "intermediate source code" but we can actually create (emit) some of it at runtime and then do the "just-in-time" compilation and execution.
- The execution is done in the context of the CLR (this is the "managed" code concept). Put another way, we can say that the runtime always "knows" what it sends for execution, contrary to a conventional environment where the code is executed directly by the operating system. This implies that you can tell the runtime to execute, or not, this or that type of code. This is the basis for code access security.
- Most of the features of the .NET languages (C#, VB, etc.) are directly related to features of the intermediate language. Put another way, most of the time, the first compilation is pretty straightforward. Some of the constructs though do not have direct equivalents in the CIL (ex. properties in C# are mapped to class methods in the CIL).
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 see MSDN.
The last thing we will note here is that the common language runtime (CLR) can execute in different contexts:
- ASP.NET for web applications, where it is directly linked to the Internet Information Server (IIS).
- Internet Explorer for client side web controls
- In a standalone host for console, service and windows applications.
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.
Where this book fits
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:
- Deployment
- Security
- Configuration
- Reflection
- Services
- Relationship with WMI
- Interoperability
- etc.
The base class library includes
- types
- collections
- generics
- text manipulation
- basic drawing
- basic globalization
- serialization
- basic input/output
- multi-threading
- etc.
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.
Programming paradigms
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.
Assemblies
According to MSDN 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.
External links
System types and collections
Exam objective: Developing applications that use system types and collections.
Topics
Programs, objects and methods
.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 the main 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.
System types
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 to execute "pre-programmed" instruction sequences
- other custom types
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. See this 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 see MSDN. And then for an overview of the class libraries (System types) see MSDN.
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.
Hello world
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 example here.
Value types
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:
- The built-in value types
- User-defined value types
- Enumerations
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
- the integer types (Byte, SByte, Int16, Int32, Int64, UInt16, UInt32 and UInt64)
- the floating point types (Single and Double)
- the logical type (Boolean)
- other (Char, Decimal, InPtr and UInPtr)
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 the Training kit (page 5) and this is not identified as an error in MSDN KB. It is not a built-in type according to the official specification (page 19). The confusion comes from the fact that the Training 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 this section. See also examples of building and using user-defined value types.
Reference types
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:
- pointers
- arrays
- classes
- interfaces
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 try this.
For other notes and an example of using reference types see this.
Arrays
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 on data 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 see C 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:
- They are fixed length
- They support only one internal organization
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 the using arrays section.
Classes
Classes are themselves split in three:
- user-defined classes
- boxed value types
- delegates
Boxed value types will be discussed a little later in the boxing / unboxing section.
Delegates will also be covered later in their section.
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 of using and building classes.
Interfaces
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 you do 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 of using and building interfaces. Some interfaces of the System namespace are shown in the standard interfaces section.
Attributes
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 the reflection 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.
The attributes 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.
See MSDN for the discussion of attributes in C#.
Collections
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:
- Using collections for the classes in the System.Collections namespace.
- Using specialized collections for the classes in the System.Collections.Specialized namespace.
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 are GotDotNet and AspNetResources
See MSDN for a general discussion on arrays, collections and data structures.
Generics
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 interesting linked article (annexes) that introduces the concept of generics in the context of generic collections. This external tutorial 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.NET Dim 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 see MSDN.
We have examples of using and building generic types.
For examples of generics collections see the using generic collections section.
Exceptions
This is how you throw a general exception:
// C# throw new Exception("This is an exception."); '// VB.NET Throw 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.NET Try Throw New Exception("This is an exception.") Catch ex As Exception Console.WriteLine(ex.Message) End Try
Events and Delegates
For the “official” discussion of events and delegates see MSDN. 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:
- You define a delegate type as a reference to functions having a specific signature
- You add an Event member to a class and associate it with the delegate type you just define, this instantiate a multicast delegate associated with the event
- When you have a reference to an object of the class you can add a reference to any method that has the same signature as the delegate type.
- When the object raises the event, the associate multicast delegate is executed which triggers the execution of the referenced function.
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 see this section.
Classes, Interfaces, and tools
Hello world example
using System;
using System.Collections.Generic;
using System.Text;
namespace HelloWorldLab1
{
class Program
{
static void Main(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.
Using System types
Exam objective: Manage data in a .NET Framework application by using the .NET Framework 2.0 system types.
(Refer System namespace)
Value types usage
Following are some "usage" oriented remarks about value types.
Value types contain the values they are assigned:
int a = 1; // the variable "a" contains "1" of value type int
Value types can also be created by using the new keyword. Using the new keyword initializes the variable with the default value obtained from the type's default constructor:
int a = new int(); // using the default constructor via the new keyword return a; // returns "0" in the case of type Int.
Value types can be declared without being initialized, but they must be initialized to some value before being used:
int a; // This is perfectly acceptable return a; // NOT acceptable! You can't use "a" because "a" doesn't have a value!
Value types cannot equal null. .NET 2.0 provides a Nullable type to get around this limitation, which is discussed in the next section, but null is not a valid value for value types:
int a = null; // Won't compile - throws an error.
If you copy a Value type to another Value type, the value is copied. 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; //the value of var1 (a "1" of type int) is copied to var2 var2 = 25; // The "1" value in var2 is overwritten with "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.
Nullable type
See MSDN
A nullable type...
- Is a generic type
- Is an instance of System.Nullable struct.
- Can only be declared on value types.
- Is declared with System.Nullable<type> or the shorthand type? - the two are interchangeable.
System.Nullable<int> MyNullableInt; // the long version int? MyNullableInt; // the short version
- Accepts the normal range of values of the underlying type, as well as null.
bool? MyBoolNullable; // valid values: true || false || null
Be careful with nullable booleans! In if, for, while or logical evaluation statements a nullable boolean will equate a null value with false—it will not throw an error.
Methods: T GetValueOrDefault() & T GetValueOrDefault(T defaultValue)
Returns the stored value or the default value if the stored value is set to null.
Properties: HasValue & Value
Nullable types have two read only properties: HasValue and Value.
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; // Error! You can't add null + 1!! if (MyInt.HasValue) MyOtherInt = MyInt.Value + 1; // This is a better way.
Value returns the value of your type, null or otherwise.
int? MyInt = 27; if (MyInt.HasValue) return MyInt.Value; // returns 27. MyInt = null; return MyInt; // returns null.
Wrapping / Unwrapping
Wrapping is the process of packaging a value m from a non-nullable type N to a nullable type N? via the expression new N?(m)
Unwrapping is the process of evaluating a nullable type N? for instance m as type N or NULL and is performed via the 'Value' property (e.g. m.Value).
Note: Unwrapping a null instance generates the exception System.InvalidOperationException
The ?? Operator (aka the Null 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 a null 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; // returns 27, since MyInt is null
For more information see the blog entry by R. Aaron Zupancic on the ?? Operator
Building a value type
Building a value type must be very simple. The following example defines a custom "point" structure with only 2 double members. See boxing 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; } }
Using a user-defined value type
The above example can be used here. Note that the p variable does not have to be initialized with the new operator.
Using enumerations
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 see MSDN
There is a special type of enumeration called a flags enumeration. The exam objectives do not mention it specifically. See MSDN 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 an enumeration
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(); } } }
Using reference types
Reference types are more commonly referred to as objects. Classes, Interfaces and Delegates are all reference types, as well as the built-in reference types System.Object and System.String. Reference types are stored in managed Heap memory.
Unlike Value types, reference types can be assigned the value null.
Copying a reference type copies a reference 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 a pointer 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); // myDog points to a position in memory. Dog yourDog = new Dog("Doberman", 3); // yourDog points to a different position in memory. yourDog = myDog; // both now point to the same position in memory, // where a Dog type has values of "Labrador" and 1 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 the String and StringBuilder classes. We have put these with the text manipulation section but manipulating strings is a basic operation of almost all programs.
Using and building arrays
See MSDN for reference information.
Using classes
Building a custom class
Using interfaces
Building a custom interface
Using attributes
Using generic types
The use of the four major categories of System Generic Types will mainly be demonstrated elsewhere in this book:
- The nullable type was discussed above
- A whole section follows on Generic collections
- The generic event handler will be discussed in the Event / Delegate section.
- The generic delegates will also be discussed in the Event / Delegate section as well as in the Generic collections section (Comparer class).
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).
Building generics
The programming of a custom generic collection was shown in the article 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:
- We don't have to recode a swap function for every type
- The generalization does not cost us the strong typing (try swapping an int and a string, it wont compile)
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" (see visitor 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 a stronger 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); } } }
Exception classes
Some links to MSDN:
- Exceptions and exception handling - MSDN
- Handling and throwing exceptions - MSDN
- Exception Hierarchy - MSDN
- Exception Class and Properties - MSDN
Boxing and unboxing
See MSDN
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.
TypeForwardedToAttribute Class
See MSDN
- For a discussion of TypeForwardToAttribute in the CLR see MSDN
- Other possible links: Marcus' Blog, NotGartner
Using Collections
Exam objective: Manage a group of associated data in a .NET Framework application by using collections.
(Refer System.Collections namespace - MSDN)
ArrayList class
see MSDN
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"); } }
Collection interfaces
- ICollection interface and IList interface
- ICollection interface - MSDN
- The ICollection interface is the base interface for classes in the System.Collections namespace.
- The ICollection interface extends IEnumerable; IDictionary and IList are more specialized interfaces that extend ICollection. An IDictionary implementation is a collection of key/value pairs, like the Hashtable class. An IList implementation is a collection of values and its members can be accessed by index, like the ArrayList class.
- Some collections that limit access to their elements, such as the Queue class and the Stack class, directly implement the ICollection interface.
- If neither the IDictionary interface nor the IList interface meet the requirements of the required collection, derive the new collection class from the ICollection interface instead for more flexibility.
- The following tables list the members exposed by the ICollection type.
- Public Properties
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.
- Public Methods
CopyTo - Copies the elements of the ICollection to an Array, starting at a particular Array index.
- IList interface - MSDN
- IComparer interface, IEqualityComparer interface, and IKeyComparer interface
- IComparer interface - MSDN
- IEqualityComparer interface - MSDN
- IKeyComparer interface - IKeyComparer does not exist in .Net 2.0
- IDictionary interface and IDictionaryEnumerator interface
- IDictionary interface - MSDN
- IDictionaryEnumerator interface - MSDN
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);
- One way of using IEnumerator.
while (Prson.MoveNext () ) { Person P = (Person)Prson.Current; Response.Write("First Name : " + P.firstName + ", Last Name : " + P.lastName); }
- One way of using IEnumerable.
People peopleList = new People(peopleArray); foreach (Person p in peopleList) Response.Write("First Name : " + p.firstName + ", Last Name : " + p.lastName);
- IHashCodeProvider interface - MSDN - Interface is now obsolete (as of .NET 2.0)
Iterators
See MSDN
- An iterator is effectively a lightweight version of the IEnumerable interface. It is primarily used with foreach statements.
- You will normally implement the GetEnumerator method of the IEnumerable interface.
public class Colors : System.Collections.IEnumerable { string[] colors = { "Red", "Green", "Blue" };
public System.Collections.IEnumerator GetEnumerator() { for (int i = 0; i < colors.Length; i++) { yield return colors[i]; } } }
- This enables the class to be accessed using a standard foreach statement. A class is not restricted to implementing only a single iterator. Multiple iterators can be supplied, for example to enable iteration in both ascending and descending order of a list. To call a named iterator, use the following syntax:
foreach (int i in myList.NamedIterator()) { System.Console.WriteLine(i); }
- The yield statement marks a point where execution of a iterator will resume on a subsequent iteration. This can be used to supply multiple yield statements:
public System.Collections.IEnumerator GetEnumerator() { yield return "Statement returned on iteration 1"; yield return "Statement returned on iteration 2"; }
- To end the iteration programmatically, use the
yield break;
- statement.
Hashtable class - MSDN
- Used to represent a collection of key/value pairs.
CollectionBase class and ReadOnlyCollectionBase class
- CollectionBase class - MSDN
- ReadOnlyCollectionBase class -MSDN
DictionaryBase class and DictionaryEntry class
- DictionaryBase class - MSDN
- DictionaryEntry structure - MSDN
Comparer class - MSDN
Queue class - MSDN
SortedList class - MSDN
BitArray class - MSDN
Stack class - MSDN
<noinclide> </noinclude>
Using generic collections
Exam objective: Improve type safety and application performance in a .NET Framework application by using generic collections.
(Refer System.Collections.Generic namespace MSDN )
Collection.Generic interfaces
- Generic IComparable interface - MSDN
- Note that IComparable<T> is a member of the System namespace.
- You use this interface when you create a class and you want it to be used with generic types that support ordering (ex. SortedList<T> or List<T>.Sort()) without having to specify a comparer object. The only method of IComparable<T> is CompareTo<T>(T other). There is an example on MSDN.
- The following example implements IComparable<T> for a custom made Point class. The example uses a List<T> instead of a SortedList<T> or OrderedDictionnary<T> because the comparaison is done based on the distance of the points from the origin which can give the same value for many points.
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() + ")"; } } }
- Generic ICollection interface and Generic IList interface
- Generic ICollection interface - MSDN
- Generic IList interface - MSDN
- Generic IComparer interface and Generic IEqualityComparer interface
- Generic IComparer interface - MSDN
- Generic IEqualityComparer interface - MSDN
- Generic IDictionary interface - MSDN
- Generic IEnumerable interface and Generic IEnumerator interface
- Generic IEnumerable interface - MSDN
- see also ONDotnet
- Generic IEnumerator interface - MSDN
- IHashCodeProvider interface - MSDN - Interface is now obsolete (as of .NET 2.0)
Generic Dictionary
- Generic Dictionary class and Generic Dictionary.Enumerator structure
- Generic Dictionary class - MSDN
- Generic Dictionary.Enumerator structure - MSDN
- Generic Dictionary.KeyCollection class and Dictionary.KeyCollection.Enumerator structure
- Generic Dictionary.KeyCollection class - MSDN
- Dictionary.KeyCollection.Enumerator structure - MSDN
- Generic Dictionary.ValueCollection class and Dictionary.ValueCollection.Enumerator structure
- Generic Dictionary.ValueCollection class - MSDN
- Dictionary.ValueCollection.Enumerator structure - MSDN
Generic Comparer class and Generic EqualityComparer class
- Generic Comparer class - MSDN
- The Comparer<T> class serves as a base class to easily implement the IComparer<T> interface.
- The example is the same then for the IComparable<T> except that now a Comparer<T> derived object is given to the List<T>.Sort() method instead of implementing the IComparable<T> interface on Point.
- This way of preceding has 2 advantages:
- It can be used even if you dont have access to the source code of Point
- You can have more than one Comparer derived class for the same Point class
- This way of preceding has 2 advantages:
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))); } } }
- Generic EqualityComparer class - MSDN
Generic KeyValuePair structure
- see MSDN
Generic List class, Generic List.Enumerator structure, and Generic SortedList class
- Generic List class - MSDN
- A generic list class instance is simply declared using the List<T> syntax where T is the specific type.
- Generic List.Enumerator structure - MSDN
- Generic SortedList class - MSDN
Generic Queue class and Generic Queue.Enumerator structure
- Generic Queue class - MSDN
- Generic Queue.Enumerator structure - MSDN
Generic SortedDictionary class
- See MSDN
- For differences between SortedList and SortedDictionary are explained see MSDN
Generic LinkedList
- A Generic Linked List represents a doubly linked list and is a general-purpose linked list. It supports enumerators and implements the ICollection interface, consistent with other classes in the .NET Framework.
- Generic LinkedList class - MSDN
- Generic LinkedList.Enumerator structure - MSDN
- Generic LinkedListNode class - MSDN
Generic Stack class and Generic Stack.Enumerator structure
- Generic Stack class - MSDN
- Generic Stack.Enumerator structure - MSDN
Using specialized collections
Exam objective: Manage data in a .NET Framework application by using specialized collections.
(Refer System.Collections.Specialized namespace)
Specialized String classes
- StringCollection class - MSDN
- StringDictionary class - MSDN
- StringEnumerator class - MSDN
Specialized Dictionary classes
- HybridDictionary class - MSDN
- IOrderedDictionary interface and OrderedDictionary class
- IOrderedDictionary Interface - MSDN
- OrderedDictionary class - MSDN
- ListDictionary class - MSDN
Named collections
- NameObjectCollectionBase class - MSDN
- NameObjectCollectionBase.KeysCollection class - MSDN
- NameValueCollection class - MSDN
CollectionsUtil class
CollectionsUtil class - MSDN
BitVector32 structure and BitVector32.Section structure
- BitVector32 structure - MSDN
- BitVector32.Section structure - MSDN
Standard interfaces
Exam objective: Implement .NET Framework interfaces to cause components to comply with standard contracts.
(Refer System namespace)
IComparable interface - MSDN
- The IComparable interface defines a comparison method that a value type or class implements to create a type-specific comparison method
IDisposable interface - MSDN
- The IDispose interface can be used to explicitly release unmanaged resources in custom classes. The consumer of an object can call this method when the object is no longer needed.
- The .Net garbage collector releases memory allocated to managed objects when they are no longer used, however, it is not possible to predict when garbage collection will occur and it has no knowledge of unmanaged resources such as window handles, or open files and streams.
IConvertible interface - MSDN
ICloneable interface - MSDN
INullableValue interface - MSDN
IEquatable interface - MSDN
IFormattable interface - MSDN
Using events and delegates
Exam objectives: Control interactions between .NET Framework application components by using events and delegates.
(Refer System namespace)
Delegate class - MSDN
- Delegates hold pointers to one or more functions and invoke them as needed.
- One common use of delegates is for event handling. A class that raises an event does not know what objects or methods want to receive the event, so an intermediary or pointer mechanism is needed between the object raising the event and the object(s) receiving the event. Delegates can be used as function pointers to accomplish this.
- A delegate is a class, but unlike a regular class it has a signature. In the .Net framework you just declare the delegate and the CLR handles the implementation of the class.
//delegate declaration public delegate void AlarmEventHandler(object sender,EventArgs e);
- The first complete example just declare a delegate type, then declare a variable of that type, assign a function to it and execute the delegate variable which has the effect of executing the function.
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; } } }
- The second delegate example implement the concept of a callback function. A function is called with a delegate as an argument. When it executes the delegate it has no knowledge of exactly what function is executed. Part of its behavior is delegated to the function passed as a parameter (thru the delegate).
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()); } } }
- The third delegate example uses a delegate member to produce the same pattern as an event. Note that executing the delegate member without assigning at least one function will cause an exception. Also assigning 2 functions with the += operator will execute the 2 functions when the delegate is executed. If the delegate has a return code, the return value of the last executed function will be returned.
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); } } }
- The fourth example is the basic example of an event. It is exactly as the third example with the event keyword added to the member declaration and a test before calling the event because of the exception thrown on an "empty" event. This example shows clearly that an event is nothing more than a multicast delegate.
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); } } }
- Executing the functions associated with an event is called raising the event.
- The functions associated with the event are called event handlers
EventArgs class - MSDN
- By convention an event uses a delegate that returns void and take 2 arguments:
- an object of type System.Object that contains a reference to the object that raised the event.
- an object from a class derived from EventArgs that contains the data passed from the object that raised the event to the event handlers.
- The EventArgs class does not contain any data by itself.
- So an event with no data will use a delegate of the form
public delegate void DelegateTypeName (object sender, EventArgs e)
- This simple event example is the same as the last one with the IntEventArgs class that serves for passing the int argument to the event handler and all the parameters changed to follow the calling convention for events.
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 and MSDN
- There are two special delegates defined in the System namespace to help you with the events declarations.
- The first is the EventHandler delegate. It passes no data. An event that passes no data can be declared as:
public event EventHandler EventName
- without having to declare a custom delegate.
- This is the usual way to declare an event that passes no data.
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); } } }
- The second is the EventHandler<T> generic delegate where T is a type derived from EventArgs
public event EventHandler<T> EventName
- again no need to declare a custom delegate type.
- This is the usual way to declare an event that passes data to the event handlers.
- Note that in this case you still have to declare the type T derived from EventArgs.
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)); } } }
- This concludes the basic examples for events and delegates.
Services, threading, and application domains
Exam objective: Implementing service processes, threading, and application domains in a .NET Framework application
Topics
Services
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:
- Doing maintenance tasks that do not need user intervention. A backup software for example will regularly check the backup schedule and execute the different backup tasks when needed. No user interface is needed for that.
- Responding to requests that come from other processes or from the operating system. An http server such as IIS (Windows component that process web requests) will receive http requests coming from client browsers and produce responses (html pages) to those same browsers. A database process is another good example. Again the http server does not need a user interface because the interface with the client is managed by the client browser component.
The exam objectives concerning services are very basic and touch the first problems that you will encounter when dealing with them:
- Since the service has no user interface then who will start and stop it? The answer is that the operating system executes the services directly but you have to ‘’register’’ your service to let the system know where it is and what to do with it (this is the installation process)
- A process with a user interface essentially waits for events coming from the user. How does a service ‘’work’’ in the absence of a message pump (the technique to get user input in a typical online application)?
- If the service does a user interface function it will “hang” waiting for a non-existent user. How can you avoid that?
The more important and complicated design issues are not covered by this exam and will be treated by the enterprise development exam.
Multithreading
Application Domain
Classes, Interfaces, and tools
Implement, install, and control a service
Exam objective: Implement, install, and control a service
(Refer System.ServiceProcess namespace)
Inherit from ServiceBase class - MSDN
- A service is a long-running executable. It does not provide a user interface, and does not require any user to be logged onto the computer. Services run as System, but it is possible to choose to have them run under a different user account. The ServiceBase class is a base class for a service. It must be derived from when creating a new service.
- Almost all services will override the OnStart and OnStop methods of ServiceBase.
ServiceController class and ServiceControllerPermission class
- ServiceController class - MSDN
- ServiceControllerPermission class - MSDN
ServiceInstaller and ServiceProcessInstaller class
- ServiceInstaller - MSDN
- ServiceProcessInstaller class - MSDN
ServiceChangeDescription structure and ServiceChangeReason enumeration
- SessionChangeDescription structure - MSDN
- SessionChangeReason enumeration - MSDN
Develop multithreaded applications
Exam objective: Develop multithreaded .NET Framework applications
(Refer System.Threading namespace)
Thread class - MSDN
ThreadPool class - MSDN
ThreadStart delegate, ParameterizedThreadStart delegate, and SynchronizationContext class
- ThreadStart delegate - MSDN
- The simplest way to create a thread is to instantiate the Thread class. The Thread constructor takes a delegate argument. The ThreadStart delegate points to a method containing your logic. For example:
Thread t1 = new Thread (new ThreadStart(LengthyLogic)); public void LengthyLogic () { // Logic code }
- ParameterizedThreadStart delegate - MSDN
- When you start a thread, sometimes you need to pass in some data for processing. .NET 2.0 provides a new delegate, ParameterizedThreadStart, which takes a parameter of type object. The class has a new overload function Thread.Start. It allows you to specify the value to be passed into the thread. This approach is simple, but is not type-safe. Example:
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 }
- SynchronizationContext class - MSDN
- The Code Project Example for SynchronizationContext Class [1]
Timeout class, Timer class, TimerCallback delegate, WaitCallback delegate, WaitHandle class, and WaitOrTimerCallback delegate
- Timeout class - MSDN
- Timer class - MSDN
- TimerCallback delegate - MSDN
- WaitCallback delegate - MSDN
- WaitHandle class - MSDN
- WaitOrTimerCallback delegate - MSDN
ThreadExceptionEventArgs class and ThreadExceptionEventHanlder class
- ThreadExceptionEventArgs class - MSDN
- ThreadExceptionEventHandler class - MSDN
ThreadState enumeration and ThreadPriority enumeration
- ThreadState enumeration - MSDN
- ThreadPriority enumeration - MSDN
ReaderWriterLock class - MSDN
AutoResetEvent class and ManualResetEvent class
- AutoResetEvent class - MSDN
- ManualResetEvent class - MSDN
IAsyncResult interface and ICancelableAsyncResult interface
- (Refer System namespace)
- IAsyncResult interface - MSDN
- ICancelableAsyncResult interface - MSDN
EventWaitHandle class, RegisterWaitHandle class, SendOrPostCallback delegate, and IOCompletionCallback delegate
- EventWaitHandle class - MSDN
- RegisterWaitHandle class - MSDN
- This is a typo in the exam list of objectives and the training kit. The term RegisterWaitForSingleObject should be saerch instead (see KB)
- SendOrPostCallback delegate - MSDN
- IOCompletionCallback delegate - MSDN
Interlocked class, NativeOverlapped structure, and Overlapped class
- Interlocked class - MSDN
- NativeOverlapped structure - MSDN
- Overlapped class - MSDN
ExecutionContext class, HostExecutionContext class, HostExecutionContext manager, and ContextCallback delegate
- ExecutionContext class - MSDN
- HostExecutionContext class - MSDN
- HostExecutionContext manager - MSDN
- In fact was is referred to here is the HostExecutionContextManager class
- ContextCallback delegate - MSDN
LockCookie structure, Monitor class, Mutex class, and Semaphore class MSDN]
- LockCookie structure - MSDN
- Monitor class - MSDN
- Mutex class - MSDN
- Semaphore class - MSDN
- Lock vs Monitor vs Mutex - MSDN
Using applications domains
Exam objective: Create a unit of isolation for common language runtime in a .NET Framework application by using application domains
(Refer System namespace)
Create an application domain
See MSDN
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");
Use AppDomain.CurrentDomain to get the application domain the calling thread is using.
Load assemblies into an application domain
See MSDN
It is possible to execute an assembly by name using AppDomain.ExecuteAssemblyByName:
AppDomain ad = AppDomain.CreateDomain("Name"); ad.ExecuteAssemblyByName("aname, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a9b8c7d6");
Or use AppDomain.ExecuteAssembly to supply a path to the assemby:
AppDomain ad = AppDomain.CreateDomain("Name"); ad.ExecuteAssembly(@"c:\path\to\file.exe");
Unload an application domain
See MSDN
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 static AppDomain.Unload function:
AppDomain ad = AppDomain.CreateDomain("Name"); AppDomain.Unload(ad);
Configure an application domain
See MSDN
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 the Internet Zone. The Internet Zone has limited permissions. To do this create a Zone 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
Retrieve setup information from an application domain
See MSDN
Use the SetupInformation 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);
Configuration, diagnostic, management, and installation
Exam objective: Embedding configuration, diagnostic, management, and installation features into a .NET Framework application
Topics
Configuration management
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.
.NET framework installer
Event log
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 see MSDN
For specifics on the EventLog class and some cautions about its use see MSDN
Performance monitoring
Debugging and tracing
Management information and events
Windows Management Instrumentation - MSDN
Classes, Interfaces, and tools
Embed configuration management
Exam objective: Embed configuration management functionality into a .NET Framework application.
(Refer System.Configuration namespace)
Configuration class and ConfigurationManager class
- Configuration class - MSDN
- ConfigurationManager class - MSDN
ConfigurationSettings class, ConfigurationElement class, ConfigurationElementCollection class, and ConfigurationElementProperty class
- ConfigurationSettings class - MSDN
- ConfigurationElement class - MSDN
- ConfigurationElementCollection class - MSDN
- ConfigurationElementProperty class - MSDN
Implement IConfigurationSectionHandler interface - MSDN
ConfigurationSection class, ConfigurationSectionCollection class, ConfigurationSectionGroup class, and ConfigurationSectionGroupCollection class
- ConfigurationSection class - MSDN
- ConfigurationSectionCollection class - MSDN
- ConfigurationSectionGroup class - MSDN
- ConfigurationSectionGroupCollection - MSDN
Implement ISettingsProviderService interface - MSDN
Implement IApplicationSettingsProvider interface - MSDN
ConfigurationValidationBase class - MSDN
- No direct result on MSDN - to be checked
Implement IConfigurationSystem interface - MSDN
Create custom installer and configure application
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).
- For a "cookbook" on for the procedures discussed in this section see MSDN and the corresponding How-To section.
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 and MSDN
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
Manage an event log
Exam objective: Manage an event log by using the System.Diagnostics namespace
EventLog class - MSDN
EventSourceCreationData class - MSDN
Write to an event log
Read from an event log
Create a new event log
You create an EventLog by creating the first event source that writes to that log.
The two simplest way to do this are:
- Use the EventLog.CreateEventSource method
- Create an EventLog instance, specify a source and then write to the log. The actual creation takes place on execution of the first write.
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 see MSDN
Manage processes and monitor performance
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.
- Process class - MSDN
- For example code for GetCurrentProcess(), GetProcessesByName(), GetProcesses(), and GetProcessById() see MSDN
Retrieve information about the current process - MSDN
Get a list of all modules loaded by a process
- The Process.Modules property returns a strongly-typed collection of ProcessModule objects that represent the Process' currently loaded modules.
- For the Process.Modules property see MSDN
- For the ProcessModule class see MSDN
PerformanceCounter class, PerformanceCounterCategory, and CounterCreationData class
- PerformanceCounter class - MSDN
- PerformanceCounterCategory - MSDN
- CounterCreationData class - MSDN
Start a process both by using and by not using command-line arguments
- Starting a Process Overview
- Processes are started using one of the overloaded Process.Start() methods. When passing sensitive data such as passwords to Process.Start(), use one of the two overloaded Start() methods that accept a SecureString as an argument type.
- External links
- MSDN2 Entry for Starting a Process - Process.Start()
- MSDN2 Entry for Starting a Process with ProcessStartInfo. This example demonstrates how to launch IE.
- MSDN2 Entry for Starting a Process with Command Line Arguments
- MSDN2 Passing a Password as a SecureString to Process.Start()
- MSDN2 SecureString class
StackTrace class - MSDN
StackFrame class - MSDN
Debug and Trace
Exam objective: Debug and trace a .NET Framework application by using the System.Diagnostics namespace.
Debug class and Debugger class
- Debug class - MSDN
- The four static writing methods of the Debug class - Write, WriteLine, WriteIf and WriteLineIf - let you write debug messages to inspect your program's flow and catch errors. Calls to these methods are ignored in the release version of your program (see 'The ConditionalAttribute attribute' below for details).
- In Visual Studio, the default target for Debug's write methods is the Output window. You can use Debug's Listeners property to access the associated TraceListenerCollection. The following code shows how to use the Remove and Add methods of the collection to control where debug messages are sent to. If you add more than one listener of the same type, the associated target receives the text multiple times.
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(); } }
- Debugger class - MSDN
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
- DebuggerBrowsableAttribute class - MSDN
- DebuggerDisplayAttribute class - MSDN
- DebuggerHiddenAttribute class - MSDN
- DebuggerNonUserCodeAttribute class - MSDN
- DebuggerStepperBoundaryAttribute class - MSDN
- DebuggerStepThroughAttribute class - MSDN
- DebuggerTypeProxyAttribute class - MSDN
- DebuggerVisualizerAttribute class - MSDN
Embed management information
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
- The classes in the System.Management namespace let you use Windows Management Instrumentation (WMI) to manage computer systems. The most notable class in this namespace is ManagementObjectSearcher, that you can use to retrieve management objects based on a WMI query.
- Information that can be retrieved this way ranges from computer case type (notebook, desktop...) over processor and hard disks details to information about running services and processes. Consult the WMI Reference on MSDN for an overview of all WMI classes and their properties.
- In the example below a rough and dirty method is defined that prints all properties for all management information objects of a given WMI class. It is then used to print information about the current computer system.
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 class - MSDN
- Enumerate all disk drivers, network adapters, and processes on a computer
- The following code uses one overload of the ManagementObjectSearcher constructor to list all physical and logical disk drives, network adapters and running processes on a system.
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); } } }
- Retrieve information about all network connections
- Example to be provided
- Retrieve information about all services that are paused
- The following code uses a ManagementObjectSearcher object to retrieve all running services and then displays their names.
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
- ObjectQuery class - MSDN
Subscribe to management events by using the ManagementEventWatcher class - MSDN
Serialization and Input/Output
Exam objective: Implementing serialization and input/output functionality in a .NET Framework application
Topics
Serialization
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.
Serializable attribute
An object is serializable if its class name is prefixed with the [Serializable] attribute.
Object Serialization
One can use the BinaryFormatter 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.
XML Serialization
One can use the XmlSerializer 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 see MSDN
Custom Serialization
The ISerializable interface allows an object to control its own serialization and deserialization.
Readers
Writers
Formatters
A formatter is used to serialize objects into streams.
Streams
File IO
Managing Byte Streams
Compression
Isolated storage
For a general discussion on IsolatedStorage tasks see MSDN
Classes, Interfaces, and tools
Serialize and deserialize
Exam objective: Serialize or deserialize an object or an object graph by using runtime serialization techniques.
(Refer System.Runtime.Serialization namespace)
Serialization interfaces
IDeserializationCallback interface - MSDN
IFormatter interface and IFormatterConverter interface
- IFormatter interface - MSDN
- IFormatterConverter interface - MSDN
ISerializable interface - MSDN
Serialization attributes
- For some serialization attributes exemple see MSDN
OnDeserializedAttribute class and OnDeserializingAttribute class
- OnDeserializedAttribute class - MSDN
- OnDeserializingAttribute class - MSDN
OnSerializedAttribute class and OnSerializingAttribute class
- OnSerializedAttribute class - MSDN
- OnSerializingAttribute class - MSDN
OptionalFieldAttribute class - MSDN
SerializationEntry structure and SerializationInfo class
SerializationEntry structure - MSDN
SerializationInfo class - MSDN
ObjectManager class
ObjectManager class - MSDN
Formatter class, FormatterConverter class, and FormatterServices class
Formatter class - MSDN
FormatterConverter class - MSDN
FormatterServices class - MSDN
StreamingContext structure
StreamingContext structure - MSDN
XML Serialization
Exam objective: Control the serialization of an object into XML format by using the System.Xml.Serialization namespace.
XmlSerializer class - MSDN
- Exam objective: Serialize and deserialize objects into XML format by using the XmlSerializer class
Control serialization by using serialization attributes - MSDN
- For a list of attributes for controlling serialization see 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
Custom serialization
Exam objective: Implement custom serialization formatting by using the Serialization Formatter classes.
SoapFormatter class - MSDN
- (Refer System.Runtime.Serialization.Formatters.Soap namespace)
BinaryFormatter class - MSDN
- (Refer System.Runtime.Serialization.Formatters.Binary namespace
File system classes
Exam objective: Access files and folders by using the File System classes.
(Refer System.IO namespace)
File class and FileInfo class
- For common IO tasks see MSDN
- File class - MSDN
- FileInfo class - MSDN
Directory class and DirectoryInfo class
- Directory class - MSDN
- DirectoryInfo class - MSDN
DriveInfo class and DriveType enumeration
- DriveInfo class - MSDN
- DriveType enumeration - MSDN
FileSystemInfo class and FileSystemWatcher class
- FileSystemInfo class
- FileSystemWatcher class
- The FileSystemWatcher class is designed to detected changes in the filesystem.
- It can be parametrised with the Filter and Path Property.
Example: FileSystemWatcher w = new FileSystemWatcher(); w.Filter = "*.txt"; w.Path = @"C:\Windows";
- The Filter property is only used to check the pattern of a file name. So do not use a directory path there.
- You can add methods such as the WaitForChanged(..) to watch for changes in the specified area.
Path class - MSDN
- The System.IO.Path class has many useful static methods for creating and parsing resource paths.
ErrorEventArgs class and ErrorEventHandler delegate
- ErrorEventArgs class - MSDN
- ErrorEventHandler delegate - MSDN
RenamedEventArgs class and RenamedEventHandler delegate
- RenamedEventArgs class - MSDN
- RenamedEventHandler delegate - MSDN
Byte streams
Exam objective: Manage byte streams by using Stream classes.
(Refer System.IO namespace)
FileStream class - MSDN
Stream class - MSDN
- System.IO.Stream is the abstract base class that all other streams inherit from. It is not possible in instantiate a Stream class. Instead use one of the other classes that derive from Stream.
- In terms of the 70-536 exam objectives, the most important classes that inherit from Stream are:
- System.IO.FileStream
- System.IO.MemoryStream
- System.IO.Compression.DeflateStream
- System.IO.Compression.GZipStream
- System.Security.Cryptography.CryptoStream
- System.IO.BufferedStream
- For a complete list of classes that inherit from Stream see MSDN.
- For a discussion on File and Stream IO see MSDN.
MemoryStream class - MSDN
BufferedStream class - MSDN
Reader and Writer classes
Exam objective: Manage the .NET Framework application data by using Reader and Writer classes.
(Refer System.IO namespace)
StringReader class and StringWriter class - MSDN and MSDN
- StringReader and StringWriter inherit from TextReader/TextWriter.
- StringReader is a TextReader for strings.
- StringWriter is a TextWriter for strings.
TextReader class and TextWriter class
- TextReader class - MSDN
- TextReader and TextWriter are abstract base classes that StreamReader, StreamWriter, StringReader, and StringWriter derive from. StreamReader and StringReader derive from TextReader. StreamWriter and StringWriter derive from TextWriter.
- TextWriter class - MSDN
StreamReader class and StreamWriter class - MSDN and MSDN
- The StreamReader and StreamWriter classes provide basic functionality for reading and writing to character-based streams (ReadLine(), WriteLine(), ReadToEnd()).
- StreamReader and StreamWriter inherit from the abstract classes TextReader and TextWriter:
- StreamReader is a TextReader of streams.
- StreamWriter is a TextWriter of streams.
- The Peek and the Read method of a StreamReader:
- The Peek-method gets the character at a certain position, but does not advance.
- The Read-method gets the character at a certain position and advances.
BinaryReader class and BinaryWriter class
- BinaryReader class - MSDN
- BinaryWriter class - MSDN
Compression and isolated storage
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
Security
Exam objective: Improving the security of the .NET Framework applications by using the .NET Framework 2.0 security features
Topics
Code 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.
Classes, interfaces, and tools
Implement code access security
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
- PermissionSet class - MSDN
- NamedPermissionSet class - MSDN
- PermissionSetCollection class
- There does not seem to be such a thing, to be investigated...
Standard Security interfaces
- IEvidenceFactory interface - MSDN
- IPermission interface - MSDN
Implement access control
Exam objective: Implement access control by using the System.Security.AccessControl classes.
DirectorySecurity class, FileSecurity class, FileSystemSecurity class, and RegistrySecurity class
- DirectorySecurity class - MSDN
- FileSecurity class - MSDN
- FileSystemSecurity class - MSDN
- RegistrySecurity class - MSDN
AccessRule class - MSDN
AuthorizationRule class and AuthorizationRuleCollection class
- AuthorizationRule class - MSDN
- AuthorizationRuleCollection class - MSDN
CommonAce class, CommonAcl class, CompoundAce class, GenericAce class, and GenericAcl class
- CommonAce class - MSDN
- CommonAcl class - MSDN
- CompoundAce class - MSDN
- GenericAce class - MSDN
- GenericAcl class - MSDN
AuditRule class - MSDN
MutexSecurity class, ObjectSecurity class, and SemaphoreSecurity class
- MutexSecurity class - MSDN
- ObjectSecurity class - MSDN
- SemaphoreSecurity class - MSDN
Implement custom authentication scheme
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 see MSDN
Encrypt, decrypt and hash data
Exam objective: Encrypt, decrypt, and hash data by using the System.Security.Cryptography classes.
(Refer System.Security.Cryptography namespace)
DES class and DESCryptoServiceProvider class
- DES class - MSDN
- DESCryptoServiceProvider class - MSDN
HashAlgorithm class - MSDN
DSA class and DSACryptoServiceProvider class
- DSA class - MSDN
- DSACryptoServiceProvider class - MSDN
SHA1 class and SHA1CryptoServiceProvider class
- SHA1 class - MSDN
- SHA1CryptoServiceProvider class - MSDN
TripleDES and TripleDESCryptoServiceProvider class
- TripleDES - MSDN
- TripleDESCryptoServiceProvider class - MSDN
MD5 class and MD5CryptoServiceProvider class
- MD5 class - MSDN
- MD5CryptoServiceProvider class - MSDN
RSA class and RSACryptoServiceProvider class
- RSA class - MSDN
- RSACryptoServiceProvider class - MSDN
RandomNumberGenerator class - MSDN
CryptoStream class - MSDN
CryptoConfig class - MSDN
RC2 class and RC2CryptoServiceProvider class
- RC2 class - MSDN
- RC2CryptoServiceProvider class - MSDN
AssymetricAlgorithm class MSDN
ProtectedData class and ProtectedMemory class
- ProtectedData class - MSDN
- ProtectedMemory class - MSDN
RijndaelManaged class and RijndaelManagedTransform class
- RijndaelManaged class - MSDN
- RijndaelManagedTransform class - MSDN
CspParameters class - MSDN
CryptoAPITransform class - MSDN
Hash-based Message Authentication Code (HMAC) - MSDN
- HMACMD5 class - MSDN
- HMACRIPEMD160 class - MSDN
- HMACSHA1 class - MSDN
- HMACSHA256 class - MSDN
- HMACSHA384 class - MSDN
- HMACSHA512 class - MSDN
Control permissions
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
- You can also set the FileIoPermisson attribute at assembly level or class level. Be then aware about the SecurityAction enumerations:
- SecurityAction.RequestRefuse: specifies the operations that should not be granted.
- SecurityAction.RequestMinumum: request for a minimum set of permissions. If not given, the app will not execute.
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
Control code privileges
Exam objective: Control code privileges by using System.Security.Policy classes.
(Refer System.Security.Policy namespace)
ApplicationSecurityInfo class and ApplicationSecurityManager class
- ApplicationSecurityInfo class - MSDN
- ApplicationSecurityManager class - MSDN
ApplicationTrust class and ApplicationTrustCollection class
- ApplicationTrust class - MSDN
- ApplicationTrustCollection class - MSDN
Evidence class and PermissionRequestEvidence class
- Evidence class - MSDN
- PermissionRequestEvidence class - MSDN
CodeGroup class, FileCodeGroup class, FirstMatchCodeGroup class, NetCodeGroup class, and UnionCodeGroup class
- CodeGroup class - MSDN
- FileCodeGroup class - MSDN
- FirstMatchCodeGroup class - MSDN
- NetCodeGroup class - MSDN
- UnionCodeGroup class - MSDN
Condition classes
- AllMembershipCondition class - MSDN
- ApplicationDirectory class and ApplicationDirectoryMembershipCondition class
- ApplicationDirectory class - MSDN
- ApplicationDirectoryMembershipCondition class - MSDN
- GacMembership class and GacMembershipCondition class
- GacMembership class
- No search results on MSDN!? a little investigation required here.
- GacMembershipCondition class - MSDN
- Hash class and HashMembershipCondition class
- Hash class - MSDN
- HashMembershipCondition class - MSDN
- Publisher class and PublisherMembershipCondition class
- Publisher class - MSDN
- PublisherMembershipCondition class - MSDN
- Site class and SiteMembershipCondition class
- Site class - MSDN
- SiteMembershipCondition class - MSDN
- StrongName class and StrongNameMembershipCondition class
- StrongName class - MSDN
- StrongNameMembershipCondition class - MSDN
- Url class and UrlMembershipConditon class
- Url class - MSDN
- UrlMembershipConditon class - MSDN
- Zone class and ZoneMembershipCondition class
- Zone class - MSDN
- ZoneMembershipCondition class - MSDN
PolicyLevel class and PolicyStatement class
- PolicyLevel class - MSDN
- PolicyStatement class - MSDN
IApplicationTrustManager interface, IMembershipCondition interface, and IIdentityPermissionFactory interface
- IApplicationTrustManager interface - MSDN
- IMembershipCondition interface - MSDN
- IIdentityPermissionFactory interface - MSDN
Access and modify identity information
Exam objective: Access and modify identity information by using the System.Security.Principal classes.
(Refer System.Security.Principal namespace)
GenericIdentity class and GenericPrincipal class
- GenericIdentity class - MSDN
- GenericPrincipal class - MSDN
WindowsIdentity class and WindowsPrincipal class
- WindowsIdentity class - MSDN
- WindowsPrincipal class - MSDN
NTAccount class and SecurityIdentifier class
- NTAccount class - MSDN
- SecurityIdentifier class - MSDN
IIdentity interface and IPrincipal interface
- IIdentity interface - MSDN
- IPrincipal interface - MSDN
WindowsImpersonationContext class - MSDN
IdentityReference class and IdentityReferenceCollection class
- IdentityReference class - MSDN
- IdentityReferenceCollection class - MSDN
Interoperability, Reflection, and Mailing
Exam objective: Implementing interoperability, reflection, and mailing functionality in a .NET Framework application
Topics
Interoperability
Reflection
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:
- get information about running assembly or assembly constituents (modules, classes, methods, etc.), this is particularly useful for dynamically loaded assemblies that are not known at compile time.
- put custom attributes in your code and retrieve those attributes at run time.
- dynamically invoke methods.
- "emit" and execute CIL code at run time.
Mailing
Classes, Interfaces, and tools
COM interoperability
Exam objective: Expose COM components to the .NET Framework and .NET Framework components to COM
(Refer System.Runtime.InteropServices namespace)
Exposing COM Components to the .NET Framework
- First there is an article in the .NET developers guide that covers the first part of this section, see MSDN
Import a type library as an assembly - MSDN
- Add references to type libraries
- Same link as above, see second paragraph.
- Type Library Importer (Tlbimp.exe) - MSDN
- Generate interop assemblies from type libraries - MSDN
- Imported Library Conversion - MSDN
- Imported Module Conversion - MSDN
- Imported Type Conversion - MSDN
- Imported Member Conversion - MSDN
- Imported Parameter Conversion - MSDN
- TypeConverter class - MSDN
Create COM types in managed code - MSDN
Compile an interop project - MSDN
Deploy an interop application - MSDN
Exposing .NET Framework Components to COM
- The rest of the objectives of that section directly refers to 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
Call DLL functions
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
- DllImportAttribute class - MSND
Call a DLL function - MSDN
- Look for "P/Invoke" on the internet.
- A good reference is: http://www.pinvoke.net/
- Some short hints:
- For the DllAttribute "CharSet", Logically, CharSet.Auto is the most secure way as this will autodetect the Charset used. The CharSet can be ANSI(Win95/Win98/ME) or Unicode (Win2000/WinXP)
- GetEntryPoint: There could be one tricky question as the EntryPoint states the method that should be called. In case the name of the method used differs from the method to be called, this flag is necessary.
Call a DLL function in special cases, such as passing structures and implementing callback functions
- Same link as above
- Passing structures - MSDN
- Implementing callback functions - MSDN
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
- MarshalAsAttribute class - MSDN
- Marshal class - MSDN
Implement Reflection
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
- AssemblyAlgorithmIdAttribute class - MSDN
- AssemblyCompanyAttribute class - MSDN
- AssemblyConfigurationAttribute class - MSDN
- AssemblyCopyrightAttribute class - MSDN
- AssemblyCultureAttribute class - MSDN
- AssemblyDefaultAliasAttribute class - MSDN
- AssemblyDelaySignAttribute class - MSDN
- AssemblyDescriptionAttribute class - MSDN
- AssemblyFileVersionAttribute class - MSDN
- AssemblyFlagsAttribute class - MSDN
- AssemblyInformationalVersionAttribute class - MSDN
- AssemblyKeyFileAttribute class - MSDN
- AssemblyTitleAttribute class - MSDN
- AssemblyTrademarkAttribute class - MSDN
- AssemblyVersionAttribute class - MSDN
Info classes
- ConstructorInfo class - MSDN
- MethodInfo class - MSDN
- MemberInfo class - MSDN
- PropertyInfo class - MSDN
- FieldInfo class - MSDN
- EventInfo class - MSDN
- LocalVariableInfo class - MSDN
Binder class and BindingFlags - MSDN
MethodBase class and MethodBody class
- MethodBase class - MSDN
- MethodBody class - MSDN
Builder classes
- AssemblyBuilder class - MSDN
- ConstructorBuilder class - MSDN
- EnumBuilder class - MSDN
- EventBuilder class - MSDN
- FieldBuilder class - MSDN
- LocalBuilder class - MSDN
- MethodBuilder class - MSDN
- ModuleBuilder class - MSDN
- ParameterBuilder class - MSDN
- PropertyBuilder class - MSDN
- TypeBuilder class - MSDN
Send Electronic mail
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
- MailAddress class - MSDN
- MailAddressCollection class - MSDN
SmtpClient class, SmtpPermission class, and SmtpPermissionAttribute class
- SmtpClient class - MSDN
- SmtpPermission class - MSDN
- SmtpPermissionAttribute class - MSDN
Attachment class, AttachmentBase class, and AttachmentCollection class
- Attachment class - MSDN
- AttachmentBase class - MSDN
- AttachmentCollection class - MSDN
SmtpException class, SmtpFailedReceipientException class, and SmtpFailedReceipientsException class
- SmtpException class - MSDN
- SmtpFailedReceipientException class - MSDN
- Please note that there is a typo in the exam objective page here, they use SmtpFailedReceipientException instead of SmtpFailedRecipientException.
- SmtpFailedRecipientsException class - MSDN
- Same typo then above
SendCompleteEventHandler delegate - MSDN
LinkedResource class and LinkedResourceCollection class
- LinkedResource class - MSDN
- LinkedResourceCollection class - MSDN
AlternateView class and AlternateViewCollection class
- AlternateView class - MSDN
- AlternateViewCollection class - MSDN
Globalization, Drawing, and Text manipulation
Exam objective: Implementing globalization, drawing, and text manipulation functionality in a .NET Framework application
Topics
Globalization
Drawing
Text manipulation
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.
String and StringBuilder classes
Text manipulation starts with the representation of a string which is done via the String 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 the StringBuilder class that serves for efficient construction.
Regular expressions
The Regex, Match and Group 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 on regular expressions which, among other things, point to this Tutorial.
Regular expressions support in .NET basically allows for:
- testing the match of a string to a regex pattern (Regex.IsMatch method)
- extracting the substrings that "match" part of a pattern (Regex.Match method with Match and Group classes).
Text encoding
Classes, Interfaces, and tools
Format data based on culture information.
(Refer System.Globalization namespace)
Access culture and region information
Exam objective: Access culture and region information in a .NET Framework application
CultureInfo class - MSDN
CultureTypes enumeration - MSDN
RegionInfo class - MSDN
Format date and time values based on the culture.
DateTimeFormatInfo class - MSDN
Format number values based on the culture.
NumberFormatInfo class - MSDN
NumberStyles enumeration - MSDN
Perform culture-sensitive string comparison.
CompareInfo class - MSDN
CompareOptions enumeration - MSDN
Custom culture
Exam objective: Build a custom culture class based on existing culture and region classes
CultureAndRegionInfoBuilder class - MSDN
CultureAndRegionModifier enumeration - MSDN
System.Drawing namespace
Exam objective: Enhance the user interface of a .NET Framework application by using the System.Drawing namespace.
Brushes, Pens, Colors and Fonts
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
Graphics, Images, Bitmaps and Icons
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
Shapes and Sizes
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
Text handling and regular expressions
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)
String class
The String class is not a specific exam objective but was added to have a place to discuss some of its characteristics.
String class - MSDN
StringBuilder class
The StringBuilder class is used for very fast string concatenation. If you use conventional string concatenation then it will run very slow because a string is held in an array. Each concatenation causes the array to increase its size and 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 string you 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
Regex class - MSDN
Match class and MatchCollection class
Match class - MSDN
MatchCollection class - MSDN
Group class and GroupCollection class
Group class - MSDN
GroupCollection class - MSDN
Encode text by using Encoding classes
Encoding class - MSDN
EncodingInfo class - MSDN
ASCIIEncoding class - MSDN
UnicodeEncoding class - MSDN
UTF8Encoding class - MSDN
Encoding Fallback classes - MSDN
Decode text by using Decoding classes.
Decoder class - MSDN
Decoder Fallback classes - MSDN
Capture class and CaptureCollection class
Capture class - MSDN
CaptureCollection class - MSDN
See also
- Microsoft Certified Professional Developer
- Introduction to .NET Framework 3.0
- Visual Basic .NET
- C# Programming
- Data Structures
References
70-536 Training kit
.NET Framework Application Development Foundation Self-Paced Training Kit, Second Edition Tony Northrup Microsoft 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 see MCPD).
If you use the training kit you might want to look here for a list of known corrections. Other potential corrections are listed in this wikibook.
C Sharp 2005
Visual C#: The language - 2005 Edition Donis Marchall Microsoft Press
Also recommended as a training aid for the 70-536 exam (for example see MCPD)
ECMA 335
If you want to go deeper into the definition of the common language infrastructure you can download the official 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.
External links
- Exam 70-536 Preparation Guide
- Microsoft .Net Framework Basics
- Lessons summaries and advice for Exam 70-536
- Multimedia training for .NET Framework Fundamentals
- .NET Resources
Annexes
The annexes are a series of articles on specific subjects that are referenced by the main text but were not integrated in it.
Annexes: Generic types
Introduction
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.
External links
- MSDN2 .NET Framework Developer's Guide : Generics in the .NET Framework
- MSDN2 C# Programmer's Reference : Generics (C# Programming Guide)
Annexes: Building custom attributes
Original text for this page authored by William "Scott" Baker
Attributes Summary
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 from System.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:
- Defining a custom attribute class, which involves:
- Assigning the AttributeUsageAttribute attribute to your class.
- Writing the code to define your custom attribute class.
- Creating the parameters for your class.
- Assigning an attribute to a code member.
- Retrieving attribute information at runtime.
Creating a Custom Attribute Class
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:
- Assigning the AttributeUsageAttribute attribute to your class.
- Writing the code to define your custom attribute class.
- Creating the parameters for your class.
Assigning the "AttributeUsageAttribute" To Your Class
Note: In Visual Basic, use of the AttributeUsageAttribute attribute is required on all custom attributes. Applying the AttributeUsageAttribute attribute to a class:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] public Class QualityCheckAttribute : System.Attribute { // ... }
Notice the use of "AttributeUsage" 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; the QualityCheckAttribute attribute could be referenced as either:
[QualityCheck] // or... [QualityCheckAttribute]
The AttributeUsageAttribute has three members: ValidOn, AllowMultiple and Inherited.
- The ValidOn member accepts AttributeTargets enum values, and restricts your attribute to the code types you specify. The default value is AttributeTargets.All. You can confine your attribute to classes, enums, return values or any of the list below:
All (any element) Delegate GenericParameter Parameter Assembly Enum Interface Property Class Event Method ReturnValue Constructor 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)]
- AllowMultiple is a boolean value that determines whether or not an attribute can be applied more than once to a given member. The default value is false. The example below illustrates multiple instances of the same attribute on an element of code:
[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 { // ... }
- The Inherited member determines whether attributes set on a class will be inherited by classes further down the inheritance tree. The default value is true:
[AttributeUsage(AttributeTargets.Class)] public class AttrOneAttribute : Attribute { // ... } // This attribute will not be inherited [AttributeUsage(AttributeTargets.Class, Inherited = false)] public class AttrTwoAttribute : Attribute { // ... } [AttrOne] [AttrTwo] public class ClassOne { // ... } // This class inherits AttrOne from ClassOne, // but not AttrTwo public class ClassTwo : ClassOne { // ... }
Defining A Custom Attribute Class
- Attributes are classes that inherit from System.Attribute, either directly or indirectly:
public Class QualityCheckAttribute : System.Attribute // direct { // ... } public Class FinalCheck : QualityCheckAttribute // indirect { // ... }
- Attribute classes have the AttributeUsageAttribute attribute:
[AttributeUsage(AllowMultiple = true, Inherited = false)] public Class QualityCheckAttribute : System.Attribute { // ... }
As previously mentioned, the use of AttributeUsageAttribute is required in VB. In C#, it is automatically applied with the default values if not declared.
Creating Parameters For An Attribute
Positional Parameters
public class QualityCheckAttribute : Attribute { public QualityCheckAttribute(string Name, string Date) // ... }
Named Parameters
public class QualityCheckAttribute : Attribute { private string _name; private string _date; private bool isApproved; public bool IsApproved { get {return isApproved;} set {isApproved = value;} } public QualityCheckAttribute(string Name, string Date) { // ... } }
Keep in mind that a variable in your code can be both a positional parameter and 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.
Assigning An Attribute To A Code Member
You have already seen examples of assigning an attribute to a code member. However, there are some points that must be clarified.
- Disambiguation is the clarification of the use of an attribute on a code member.
- Syntax - there is more than one way to apply multiple attributes.
Disambiguation
public class MyAttribute : Attribute { [SomeAttribute("Hello")] 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 the return value:
public class MyAttribute : Attribute { [return : 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.
Declaration Possible targets assembly assembly module module class type struct type interface type enum type delegate type, return method method, return parameter param field field property — indexer property property — get accessor method, return property — set accessor method, param, return event — field event, field, method event — property event, property event — add method, param event — remove method, param *Reference: Disambiguating Attribute Targets (C# Programming Guide)
One would think that the AttributeUsageAttribute's AttributeTargets in an attribute's definition would help to prevent this confusion: one would be wrong. The compiler does not use the AttributeUsageAttribute information when resolving conflicts. Even if you define an attribute to apply only to a specific type, for instance AttributeTargets.Return, you must still clarify that it applies to the return type when applying the attribute or the compiler will use the default target method type, and throw an error.
Syntax: Applying Multiple Attributes
[AttrOne(...), AttrTwo(...)] // or... [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(...)] // <-- invalid! // instead, you must... [return : AttrOne(...)] [method : AttrTwo(...)]
Retrieving Attribute Information At Runtime
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:
- Retrieve a single attribute from a member.
- Retrieve multiple attributes from a member.
- Retrieve attributes of a single type from multiple members.
Retrieving A Single Attribute From A Member
To access attribute information:
- Declare an instance of the attribute type.
- Use the Attribute.GetCustomAttribute(type, typeof) method to read the attribute into the instance.
- Use the properties of the instance to read the values.
The example code below declares a class ExampleClass with a QualityCheck attribute. The GetSingleAttribute method accepts a target member type and the type of attribute you're looking for. The Attribute.GetCustomAttribute method retrieves the attribute information into the attr object, from which we can read the all-important IsApproved 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.GetCustomAttribute(targetType, typeof(attrType)); if (attr == null) { //... } else { Console.Writeline(attr.IsApproved); } }
An important factor to keep in mind is that the GetCustomAttribute method is designed to read one and only one attribute. GetCustomAttribute actually checks to see if more than one attribute matches - if there is no match it returns null, but if there is more than one match it will throw an AmbiguousMatchException. When checking for attributes the only time it is safe to use GetCustomAttribute is when the attribute's definition states [AttributeUsage(AllowMultiple=false)].
Retrieving Multiple Attributes From A Member
Reading multiple instances of an attribute on a member isn't much different than reading one; to read multiple attributes use the plural GetCustomAttributes, 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); }
Retrieving A Single Attribute Type From Multiple Members
What if you want to do something a little more complex, like checking each method in a class for a QualityCheck attribute? Thanks to the System.Reflection namespace, we don't have to even break a sweat. Simply read all the members (methods, in this instance) into a MemberInfo array and iterate through them:
using System.Reflection 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); } } } }