|
Introduction
Requirements
- Visual Studio.NET Professional, or Enterprise Architect Edition
- VB.NET or C#.NET Programming Knowledge
- Read Article, "Microsoft.NET CodeDom Technology - Part 1"
This article introduces some complementary concepts to CodeDom: Attributes and Reflection. Attributes allow you to clarify the usage or structure of the element it is applied to. Reflection allows you to examine the meta-data of an element at run-time.
You will study each concept presented independently, and you will complete programming exercises using each concept presented. The programming exercises will then be explained line by line to complete your understanding of the concept presented. The first concept you will learn about is the Attribute.
Attributes Overview
Attributes are discrete pieces of information, applied to a programming element that clarifies the usage or structure of the element. In other words, attributes are pieces of information, sometimes called "meta-data" that describe the element they are applied to. There are two types of attributes: Standard Attributes and Custom Attributes. An element can consume both Standard and Custom Attributes simultaneously. Standard attributes are intrinsic to the .NET Framework. There are various intrinsic attributes available for use, depending upon the element being used. You can see an example of an intrinsic attribute in the "AttributeUsage" element in Line #1 of Listing 2.2. Custom Attributes are created by deriving your own class from the System.Attribute class and then restricting which elements are allowed to consume your attribute by setting the value of the System.Attribute.AttributeTargets enumeration, located in the System.Attribute namespace. The System.Attribute.AttributeTargets enumeration lists which element types are allowed to consume your custom attribute. Attributes can accept parameters. There are two types of parameters: Positional and Named parameters. Positional Parameters are declared every time the attribute is applied to an element, and are input to the constructor defining the attribute. Named Parameters are optional parameters. To set the value of a Named Parameter, you must use the exact name of the parameter and supply a value for it. The table below lists the properties and methods of the System.Attribute class.
System.Attribute Class
The System.Attribute class contains methods for creating and testing custom attributes. All custom attributes must derive from the System.Attribute class. The attributes you declare become part of the meta-data of the application at compile-time and can be interrogated at runtime using reflection.
|
System.Attribute Public Properties |
|
TypeId
|
When implemented in a derived class, gets a unique identifier for this Attribute.
|
|
System.Attribute Public Methods |
|
Equals |
Overridden. See Object.Equals. |
|
GetCustomAttribute |
Overloaded. Retrieves a custom attribute of a specified type applied to a specified member of a class. |
|
GetCustomAttributes |
Overloaded. Retrieves an array of the custom attributes of a specified type applied to a specified member of a class. |
|
GetHashCode |
Overridden. Returns the hash code for this instance. |
|
GetType |
Gets the Type of the current instance. |
|
IsDefaultAttribute |
When overridden in a derived class, returns an indication whether the value of this instance is the default value for the derived class. |
|
IsDefined |
Overloaded. Determines whether any custom attributes of a specified type are applied to a specified member of a class. |
|
Match |
When overridden in a derived class, returns a value indicating whether this instance equals a specified object. |
|
ToString |
Returns a String that represents the current Object. |
|
System.Attribute Protected Constructors
|
|
Attribute Constructor |
Initializes a new instance of the Attribute class. |
| |
|
|
System.Attribute Protected Methods
|
|
Finalize |
Overridden. Allows an Object to attempt to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection. |
|
MemberwiseClone |
Creates a shallow copy of the current Object. |
System.Attribute.AttributeTargets Enumeration
The System.Attributes.AttributeTargets enumeration defines the application elements allowed to consume your new attribute. You can apply multiple attributes to the same element by combining the attributes using the "OR" operator. When defining your new attribute, it is important to restrict the types of programming elements allowed to consume your attribute by setting the value of the System.Attribute.AttributeTargets Enumeration, located in the System.Attribute namespace.
|
System.Attribute.AttributeTargets Enumeration |
|
All |
Attribute can be applied to any application element. |
|
Assembly |
Attribute can be applied to an assembly. |
|
Class |
Attribute can be applied to a class. |
|
Constructor |
Attribute can be applied to a constructor. |
|
Delegate |
Attribute can be applied to a delegate. |
|
Enum |
Attribute can be applied to an enumeration. |
|
Event |
Attribute can be applied to an event. |
|
Field |
Attribute can be applied to a field. |
|
Interface |
Attribute can be applied to an interface. |
|
Method |
Attribute can be applied to a method. |
|
Module |
Attribute can be applied to a portable execution file (.dll, or.exe) |
|
Parameter |
Attribute can be applied to a parameter. |
|
Property |
Attribute can be applied to a property. |
|
ReturnValue |
Attribute can be applied to a return value. |
|
Struct |
Attribute can be applied to a structure; that is, a value type. |
Attributes Programming Example
In this example, you will create a new attribute for the CodeDom Source Listing 1.5, from part one of this article titled, "Microsoft.NET CodeDom Technology - Part 1."
Listing 2.1 Attribute CodeDom Source
1: public void CreateCodeDomSecurityStateAttribute()
2: {
3: //Initialize CodeDom Variables
4: Stream s = File.Open("c:\\" + "SecurityStateAttribute" + ".cs",
FileMode.Create);
5: StreamWriter sw = new StreamWriter(s);
6:
7: CSharpCodeProvider cscProvider = new CSharpCodeProvider();
8: ICodeGenerator cscg = cscProvider.CreateGenerator(sw);
9: CodeGeneratorOptions cop = new CodeGeneratorOptions();
10: cop.BracingStyle = "C";
11:
12: //Generate [AttributeUsage] Attribute
13: CodeSnippetCompileUnit csu1 = new
CodeSnippetCompileUnit("[AttributeUsage(AttributeTargets.Class)]");
14: cscg.GenerateCodeFromCompileUnit(csu1, sw, cop);
15:
16: //Generate Class Definition
17: CodeTypeDeclaration ctd = new CodeTypeDeclaration();
18: ctd.IsClass = true;
19: ctd.Name = "SecurityState";
20: ctd.BaseTypes.Add("Attribute");
21: ctd.TypeAttributes = TypeAttributes.Public;
22:
23: //Generate Comment
24: CodeCommentStatement ccs1 = new CodeCommentStatement("Positional Attribute
Parameter");
25:
26: Generate Member Field
27: CodeMemberField cmfSecurityState = new CodeMemberField("System.Int32",
"m_SecurityState");
28: cmfSecurityState.Attributes = MemberAttributes.Private;
29: cmfSecurityState.Comments.Add(ccs1);
30: ctd.Members.Add(cmfSecurityState);
31:
32: //Generate Comment
33: CodeCommentStatement ccs4 = new CodeCommentStatement("Constructor");
34:
35: //Generate Constructor
36: CodeConstructor ccon = new CodeConstructor();
37: ccon.Attributes = MemberAttributes.Public;
38: CodeParameterDeclarationExpression cparam1 = new
39:
CodeParameterDeclarationExpression("System.Int32","SecurityLevel");
40: ccon.Parameters.Add(cparam1);
41: ccon.Comments.Add(ccs4);
42:
43: //Create Case 0 If Statement
44: CodeConditionStatement codecond1 = new CodeConditionStatement(new
45: CodeSnippetExpression("SecurityLevel == 0"), new
CodeSnippetStatement("m_SecurityState = 0;"));
46:
47:
48: //Create Case 1 If Statement
49: CodeConditionStatement codecond2 = new CodeConditionStatement(new
50: CodeSnippetExpression("SecurityLevel == 1"), new
CodeSnippetStatement("m_SecurityState = 1;"));
51:
52:
53: //Create Case 2 If Statement
54: CodeConditionStatement codecond3 = new CodeConditionStatement(new
55: CodeSnippetExpression("SecurityLevel == 2"), new
CodeSnippetStatement("m_SecurityState = 2;"));
56:
57:
58: //Create Case 3 If Statement
59: CodeConditionStatement codecond4 = new CodeConditionStatement(new
60: CodeSnippetExpression("SecurityLevel == 3"), new
CodeSnippetStatement("m_SecurityState = 3;"));
61:
62:
63: //Create Case 4 If Statement
64: CodeConditionStatement codecond5 = new CodeConditionStatement(new
65: CodeSnippetExpression("SecurityLevel == 4"), new
CodeSnippetStatement("m_SecurityState = 4;"));
66:
67:
68: //Create Case 5 If Statement
69: CodeConditionStatement codecond6 = new CodeConditionStatement(new
70: CodeSnippetExpression("SecurityLevel == 5"), new
CodeSnippetStatement("m_SecurityState = 5;"));
71:
72:
73: //Add If Statements to Constructor Body
74: ccon.Statements.Add(codecond1);
75: ccon.Statements.Add(codecond2);
76: ccon.Statements.Add(codecond3);
77: ccon.Statements.Add(codecond4);
78: ccon.Statements.Add(codecond5);
79: ccon.Statements.Add(codecond6);
80:
81: //Generate Source Code File
82: ctd.Members.Add(ccon);
83: cscg.GenerateCodeFromType(ctd, sw, cop);
84:
85: //Close StreamWriter
86: sw.Close();
87: s.Close();
88: }
Listing 2.2 Attribute Source Generated
1: [AttributeUsage(AttributeTargets.Class)]
2: public class SecurityState : Attribute
3: {
4:
5: // Positional Attribute Parameter
6: private int m_SecurityState;
7:
8: // Constructor
9: public SecurityState(int SecurityLevel)
10: {
11: if (SecurityLevel == 0)
12: {
13: m_SecurityState = 0;
14: }
15: if (SecurityLevel == 1)
16: {
17: m_SecurityState = 1;
18: }
19: if (SecurityLevel == 2)
20: {
21: m_SecurityState = 2;
22: }
23: if (SecurityLevel == 3)
24: {
25: m_SecurityState = 3;
26: }
27: if (SecurityLevel == 4)
28: {
29: m_SecurityState = 4;
30: }
31: if (SecurityLevel == 5)
32: {
33: m_SecurityState = 5;
34: }
35: }
36: }
Attribute Example Explanation (CodeDom) - Listing 2.1
1: public void CreateCodeDomSecurityStateAttribute()
2: {
3: //Initialize CodeDom Variables
4: Stream s = File.Open("c:\\" + "SecurityStateAttribute" + ".cs",
FileMode.Create);
5: StreamWriter sw = new StreamWriter(s);
Line #4: This line creates a Stream object , which we will use for channeling data into a file.
Line #5: This line creates a StreamWriter object. Once you have created a Stream object to handle the data channeling, you need a StreamWriter to handle the physical writing of the bits to and from a data source - a file in this case.
7: CSharpCodeProvider cscProvider = new CSharpCodeProvider();
8: ICodeGenerator cscg = cscProvider.CreateGenerator(sw);
9: CodeGeneratorOptions cop = new CodeGeneratorOptions();
10: cop.BracingStyle = "C";
Line #7: This line creates an instance of the CSharpCodeProvider class. If you want to use the CodeDom classes in your own projects, you must point the CodeDom namespaces to a class that conforms to the CodeDom specification and that provides the functionality to generate source code in the language you select. In our case, Line 7 above tells us that the CSharpCodeProvider Class contains the necessary functionality to dynamically create source code in C# using CodeDom. The CSharpCodeProvider class contains the necessary plumbing to support code generation that targets the C# programming language using CodeDom.
Line #8: This line declares an instance of the ICodeGenerator interface, which is responsible for logically creating the CodeDom tree structures and CompileUnits as in-memory structures.
Line #9: This line creates a CodeGeneratorOptions object. This object is responsible for setting configuration properties for structuring the physical source code file on disk. Common properties that are set using the CodeGeneratorOptions class include how many characters to indent, the indent character and what style of bracing to use. In our case, since we did not specify any configuration properties, and since we are targeting C# as our default language, the defaults for the CodeGeneratorOptions class were used - "C" Style bracing, and tab character indentations.
12: //Generate [AttributeUsage] Attribute
13: CodeSnippetCompileUnit csu1 = new
CodeSnippetCompileUnit("[AttributeUsage(AttributeTargets.Class)]");
14: cscg.GenerateCodeFromCompileUnit(csu1, sw, cop);
Line #13: This line creates an instance of the CodeSnippetCompileUnit class. This class is responsible for creating, manipulating and searching CodeDom trees. Remember that the "Snippet" classes are a "catch-all" for generating source code. Here, we have used an instance of the CodeSnippetCompileUnit Class to generate our "AttributeUsage" attribute and to set the value of the AttributeTargets.Class Enumerated value. Since a snippet class represents literal text to be written to the CodeDom tree, we will be inserting the literal string ""[AttributeUsage(AttributeTargets.Class)]" into our final CodeDom output.
Line #14: Once a conceptual placeholder for our attribute has been created, the next step is to translate it into C# source code. The statement on line #14 accomplishes the task of using our code generator to generate source code for our attribute using our CodeSnippetCompileUnit definition.
16: //Generate Class Definition
17: CodeTypeDeclaration ctd = new CodeTypeDeclaration();
18: ctd.IsClass = true;
19: ctd.Name = "SecurityState";
20: ctd.BaseTypes.Add("Attribute");
21: ctd.TypeAttributes = TypeAttributes.Public;
Line #17,18,19,20,21: These lines create a CodeTypeDeclaration object. In CodeDom we build our CodeDom trees using specific types of programming constructs - hence the name "type". CodeTypeDeclaration objects are generic, language-independent representations of a specific type of programming construct. Examples of programming construct types include: classes, structures, and interfaces. Lines #18-21 identify and configure the specific type of programming construct we wish to create in our CodeDom tree. One point of interest is Line #20. Remember that every custom attribute you define must derive from the System.Attribute class. Line #20 configures the base type of our custom attribute class to be the "Attribute" class. This forms the inheritance relationship in the final generated code. (See Line #2 of Listing 2.2).
23: //Generate Comment
24: CodeCommentStatement ccs1 = new CodeCommentStatement("Positional Attribute
Parameter");
Line #24: This line creates a conceptual placeholder for a single line comment in our CodeDom tree by creating an instance of the CodeCommentStatement class. The literal text inserted into the constructor of this object is the text that will be written to the final CodeDom output.
26: Generate Member Field
27: CodeMemberField cmfSecurityState = new CodeMemberField("System.Int32",
"m_SecurityState");
28: cmfSecurityState.Attributes = MemberAttributes.Private;
29: cmfSecurityState.Comments.Add(ccs1);
30: ctd.Members.Add(cmfSecurityState);
Line #27: This line creates a member field construct. Notice that the data type of this member field was declared as type "System.Int32" as opposed to just "int". When declaring data types using CodeDom, you should try to use the "System.xxx" format whenever possible - this is due to how the CodeProvider class for the language you are targeting handles data types.
Line #28,29,30: These lines configure the member field declared in Line #27 above. Once the member field has been declared, we set the scope of it (Line#28), add a comment (Line #29), and then add the member field to the class definition created in Line #17 above.
32: //Generate Comment
33: CodeCommentStatement ccs4 = new CodeCommentStatement("Constructor");
34:
35: //Generate Constructor
36: CodeConstructor ccon = new CodeConstructor();
37: ccon.Attributes = MemberAttributes.Public;
38: CodeParameterDeclarationExpression cparam1 = new
39:
CodeParameterDeclarationExpression("System.Int32","SecurityLevel");
40: ccon.Parameters.Add(cparam1);
41: ccon.Comments.Add(ccs4);
Line #33: This line creates a comment statement with the literal value of "Constructor". Since we are targeting C# as our target language, the result will be a C# style, single-line comment.
Line #36: This line creates a logical placeholder for a new constructor element for a class definition. Because classes must have a constructor, we are required to declare our own class constructor for our custom attribute class, which is derived from the System.Attribute class.
Line #37: This line sets the scope of our new class constructor to have a public scope.
Line #38: Our class will be a parameterized constructor ; therefore, we will need to define the parameters to our constructor. The CodeParameterDeclarationExpression CodeDom class provides this functionality for us. In Line #38, we declare a parameter with a data type of "System.Int32" and name of "SecurityLevel". Again, notice that the data type of this parameter was declared as type "System.Int32" as opposed to just "int". When declaring data types using CodeDom, you should try to use the "System.xxx" format whenever possible. This is due to how the CodeProvider Class for the language you are targeting understands and translates data types.
Line #40: This line adds our constructor parameter declaration, defined in line #38, to our constructor. If we failed to add the contents of line #40 to our CodeDom tree, it would not appear in our final output.
Line #41: This line adds the comment construct declared on line #33 to our constructor, and to the final CodeDom output tree. Again, if we failed to add the comment to the CodeDom tree, the comment would not appear in the final source code output.
43: //Create Case 0 If Statement
44: CodeConditionStatement codecond1 = new CodeConditionStatement(new
45: CodeSnippetExpression("SecurityLevel == 0"), new
CodeSnippetStatement("m_SecurityState = 0;"));
46:
47:
48: //Create Case 1 If Statement
49: CodeConditionStatement codecond2 = new CodeConditionStatement(new
50: CodeSnippetExpression("SecurityLevel == 1"), new
CodeSnippetStatement("m_SecurityState = 1;"));
51:
52:
53: //Create Case 2 If Statement
54: CodeConditionStatement codecond3 = new CodeConditionStatement(new
55: CodeSnippetExpression("SecurityLevel == 2"), new
CodeSnippetStatement("m_SecurityState = 2;"));
56:
57:
58: //Create Case 3 If Statement
59: CodeConditionStatement codecond4 = new CodeConditionStatement(new
60: CodeSnippetExpression("SecurityLevel == 3"), new
CodeSnippetStatement("m_SecurityState = 3;"));
61:
62:
63: //Create Case 4 If Statement
64: CodeConditionStatement codecond5 = new CodeConditionStatement(new
65: CodeSnippetExpression("SecurityLevel == 4"), new
CodeSnippetStatement("m_SecurityState = 4;"));
66:
67:
68: //Create Case 5 If Statement
69: CodeConditionStatement codecond6 = new CodeConditionStatement(new
70: CodeSnippetExpression("SecurityLevel == 5"), new
CodeSnippetStatement("m_SecurityState = 5;"));
Line #44,45,49,50,54,55,59,60,64,65,69,70: These lines create the "If" statements in the final CodeDom tree. Notice the CodeConditionStatement class. The CodeDom class typically represents a simple decision statement such as an "If" statement. You might ask why the "Switch" construct was not used to represent the code above? The answer is simple - for demonstration purposes it is easier to use "If" statements. If you feel adventurous, try to rewrite the code in lines #43-70 above using a "Switch" construct. You will find it a useful exercise in learning CodeDom.
73: //Add If Statements to Constructor Body
74: ccon.Statements.Add(codecond1);
75: ccon.Statements.Add(codecond2);
76: ccon.Statements.Add(codecond3);
77: ccon.Statements.Add(codecond4);
78: ccon.Statements.Add(codecond5);
79: ccon.Statements.Add(codecond6);
Line #74,75,76,77,78,79: These lines take the "If" statements, defined in lines #43-70 above, and add them to the constructor element. All that remains is to add our constructor to the class defined in line #17 above. We will do this next.
81: //Generate Source Code File
82: ctd.Members.Add(ccon);
83: cscg.GenerateCodeFromType(ctd, sw, cop);
84:
85: //Close StreamWriter
86: sw.Close();
87: s.Close();
88: }
Line #82: This line adds our constructor to the class declared in Line #17 above. We are now finished building our CodeDom tree. Next, we need to convert our CodeDom tree into source code. Remember that we are targeting C# as our output language, but you could just as easily choose any .NET compliant language that conforms to the specifications of .NET.
Line #83: The CodeGenerator class of our target language generates the physical source code. To process our CodeDom tree, we need to execute the "GenerateCodeFromType" method of the CodeGenerator class. This method accepts three parameters: The type construct we want to generate code for (a class in our case); the StreamWriter object to use for writing the physical bits to our source code output file, and an object representing the options to use when writing the source code to disk - such as indentations and bracing style (since we are targeting C# as our language of choice) . You should now see a file named "SecurityStateAttribute.cs" located on your C: drive root. The contents of this file should mirror the source code in Listing 2.2 below.
Attribute Example Explanation (CodeDom Output) - Listing 2.2
1: [AttributeUsage(AttributeTargets.Class)]
2: public class SecurityState : Attribute
3: {
Line #1: This line declares an instance of the "AttributeUsage" attribute, which is intrinsic to the .NET Framework. It is used when creating your own custom attributes. When creating your own attributes, you must derive your attribute class from the System.Attribute class located in the System namespace. You must also provide the functionality of your attribute to complete its definition and indicate which programming elements are allowed to consume your attribute. This is done by setting the parameter of the "AttributeUsage" to a value in the "AttributeTargets" enumeration. The "AttributeTargets" enumeration lists the programming elements you can use to restrict which elements are allowed to consume your attribute. The values of the System.Attribute.AttributeTargets enumeration are listed above. In line #1, the enumerated value "AttributeTargets.Class" indicates that only class elements may consume your attribute. Applying your attribute to any programming element, other than the enumerated values provided in the parameter of the AttributeUsage attribute, will result in an error. In summary, the "AttributeUsage" attribute allows either full or restricted usage of your new attribute. The AttributeTargets enumeration values restrict which elements may consume your attribute.
Line #2: This line declares a custom attribute class. Remember that custom attributes must derive from the System.Attribute class. Thus, line #2 declares a new custom attribute class called "SecurityState", which derives from the System.Attribute class. The Framework is now aware of the presence of our attribute class.
5: // Positional Attribute Parameter
6: private int m_SecurityState;
Line #6: This line declares a private member field called "m_SecurityState" to store the state of our attribute. This field is initialized when the attribute class constructor is invoked. Since the state of our attribute is defined to be an integer, the member field is declared as data type "int". We also set the scope of the field to be private since we do not want to expose this field to other external classes, assemblies or methods. The "m_SecurityState" field will appear in the meta-data portion of our assembly at compile-time. In the next section of this article, you will learn how to examine an assembly's meta-data by using a process called Reflection.
8: // Constructor
9: public SecurityState(int SecurityLevel)
10: {
Line #9: This line declares our attribute constructor. The constructor receives a single parameter of type "int". This parameter value initializes the "m_SecurityState" member field from within the constructor body.
11: if (SecurityLevel == 0)
12: {
13: m_SecurityState = 0;
14: }
15: if (SecurityLevel == 1)
16: {
17: m_SecurityState = 1;
18: }
19: if (SecurityLevel == 2)
20: {
21: m_SecurityState = 2;
22: }
23: if (SecurityLevel == 3)
24: {
25: m_SecurityState = 3;
26: }
27: if (SecurityLevel == 4)
28: {
29: m_SecurityState = 4;
30: }
31: if (SecurityLevel == 5)
32: {
33: m_SecurityState = 5;
34: }
35: }
36: }
Line 11,15,19,23,27,31: These lines assign the value of the "m_SecurityState" member field to whatever value was passed in to the SecurityState attribute constructor. For example, if SecurityState is equal to zero, then the m_SecurityState field will be assigned a value of zero.
Reflection Overview
Reflection allows you to do the following at runtime: view type information, examine the structure of specific types, dynamically load and use types, and access custom attributes. The Type class is the main class you will use when implementing Reflection in your own applications. You can use the Type object's methods, fields, properties and nested classes to find out most information needed about any type. Reflection is highly useful if you want to find out if a local or remote component supports specific functionality. For example, if you want to use another developer's component, but do not know if the component implements a specific method, you can examine the component using the MethodInfo class to search for the method you wish to execute. The most commonly used Reflection classes include: the Assembly, Module, ConstructorInfo, MethodInfo, FieldInfo, EventInfo, PropertyInfo, and ParameterInfo classes. In the programming examples that follow, you will see how to retrieve common Reflection meta-data elements that contain many types of useful information.
In summary, you can use Reflection to examine the programming types and constructs in your applications and determine their functionality, structure, or usage. Your applications may take a small performance hit when using Reflection, but based upon how frequently you make reflection-based calls and based on your need to interrogate the usage, structure or functionality of an element, the performance penalty will vary. When applied properly, Reflection is a powerful construct available to you in your own applications.
System.Reflection Namespace Overview
The System.Reflection namespace provides classes, properties, methods and events for providing a "point-in-time" view of type elements. This namespace also allows you to dynamically create types and dynamically invoke type constructs at runtime. The most commonly used classes from the System.Reflection namespace include the Assembly, Module, ConstructorInfo, MethodInfo, FieldInfo, EventInfo, PropertyInfo, and ParameterInfo classes. The table below lists the other classes, interfaces, structures, delegates, and enumerations contained within the System.Reflection namespace.
NOTE: MS Help documentaion must be installed for the URLs in the following table to work.
|
System.Reflection Classes |
|
AmbiguousMatchException |
The exception that is thrown when binding to a method results in more than one method matching the binding criteria. |
|
Assembly |
Defines an Assembly, which is a reusable, versionable, and self-describing building block of a common language runtime application. |
|
AssemblyAlgorithmIdAttribute |
Specifies an algorithm to hash all files in an assembly. This class cannot be inherited. |
|
AssemblyCompanyAttribute |
Defines a company name custom attribute for an assembly manifest. |
|
AssemblyConfigurationAttribute |
Defines an assembly configuration custom attribute (such as retail or debug) for an assembly manifest. |
|
AssemblyCopyrightAttribute |
Defines a copyright custom attribute for an assembly manifest. |
|
AssemblyCultureAttribute |
Specifies which culture the assembly supports. |
|
AssemblyDefaultAliasAttribute |
Defines a friendly default alias for an assembly manifest. |
|
AssemblyDelaySignAttribute |
Specifies that the assembly is not fully signed when created. |
|
AssemblyDescriptionAttribute |
Defines an assembly description custom attribute for an assembly manifest. |
|
AssemblyFileVersionAttribute |
Instructs a compiler to use a specific version number for the Win32 file version resource. The Win32 file version is not required to be the same as the assembly's version number. |
|
AssemblyFlagsAttribute |
Specifies whether an assembly supports side-by-side execution on the same machine, in the same process, or in the same application domain. This class cannot be inherited. |
|
AssemblyInformationalVersionAttribute |
Defines an assembly informational version custom attribute for an assembly manifest. |
|
AssemblyKeyFileAttribute |
Specifies the name of a file containing the key pair used to generate a shared name. |
|
AssemblyKeyNameAttribute |
Specifies the name of a key container within the CSP containing the key pair used to generate a strong name. |
|
AssemblyName |
Fully describes an assembly's unique identity. |
|
AssemblyNameProxy |
Provides a remotable version of the AssemblyName. |
|
AssemblyProductAttribute |
Defines a product name custom attribute for an assembly manifest. |
|
AssemblyTitleAttribute |
Defines an assembly title custom attribute for an assembly manifest. |
|
AssemblyTrademarkAttribute |
Defines a trademark custom attribute for an assembly manifest. |
|
AssemblyVersionAttribute |
Specifies the version of the assembly being attributed. |
|
Binder |
Selects a member from a list of candidates, and performs type conversion from actual argument type to formal argument type. |
|
ConstructorInfo |
Discovers the attributes of a class constructor and provides access to constructor metadata. |
|
CustomAttributeFormatException |
The exception that is thrown when the binary format of a custom attribute is invalid. |
|
DefaultMemberAttribute |
Defines the member of a type that is the default member used by InvokeMember. The default member is a name given to a type. |
|
EventInfo |
Discovers the attributes of an event and provides access to event metadata. |
|
FieldInfo |
Discovers the attributes of a field and provides access to field metadata. |
|
InvalidFilterCriteriaException |
The exception that is thrown in FindMembers when the filter criteria is not valid for the type of filter you are using. |
|
ManifestResourceInfo |
Contains manifest resource topology information. |
|
MemberInfo |
Discovers the attributes of a member and provides access to member metadata. |
|
MethodBase |
Provides information about methods and constructors. |
|
MethodInfo |
Discovers the attributes of a method and provides access to method metadata. |
|
Missing |
Represents a missing Object. This class cannot be inherited. |
|
Module |
Performs reflection on a module. |
|
ParameterInfo |
Discovers the attributes of a parameter and provides access to parameter metadata. |
|
Pointer |
Provides a wrapper class for pointers. |
|
PropertyInfo |
Discovers the attributes of a property and provides access to property metadata. |
|
ReflectionTypeLoadException |
The exception that is thrown by the Module.GetTypes method if any of the classes in a module cannot be loaded. This class cannot be inherited. |
|
StrongNameKeyPair |
Encapsulates access to a public or private key pair used to sign strong name assemblies. |
|
TargetException |
Represents the exception that is thrown when an attempt is made to invoke an invalid target. |
|
TargetInvocationException |
The exception that is thrown by methods invoked through reflection. This class cannot be inherited. |
|
TargetParameterCountException |
The exception that is thrown when the number of parameters for an invocation does not match the number expected. This class cannot be inherited. |
|
TypeDelegator |
Wraps a Type object and delegates all methods to that Type. |
|
System.Reflection Interfaces |
|
ICustomAttributeProvider |
Provides custom attributes for reflection objects that support them. |
|
IReflect |
Allows objects to return MemberInfo objects that represent an object. |
|
System.Reflection Structures |
|
InterfaceMapping |
Retrieves the mapping of an interface into the actual methods on a class that implements that interface. |
|
ParameterModifier |
Attaches a modifier to parameters so that binding can work with parameter signatures in which the types have been modified. |
|
System.Reflection Delegates |
|
MemberFilter |
Represents a delegate that is used to filter a list of members represented in an array of MemberInfo objects. |
|
ModuleResolveEventHandler |
Represents the method that will handle the event handler. |
|
TypeFilter |
Filters the classes represented in an array of Type objects. |
|
System.Reflection Enumerations |
|
AssemblyNameFlags |
Provides information about an Assembly reference. |
|
BindingFlags |
Specifies flags that control binding and the way in which the search for members and types is conducted by reflection. |
|
CallingConventions |
Defines the valid calling conventions for an enumeration. |
|
EventAttributes |
Specifies the attributes of an event. |
|
FieldAttributes |
Specifies flags that describe the attributes of a field. |
|
MemberTypes |
Marks each type of member that is defined as a derived class of MemberInfo. |
|
MethodAttributes |
Specifies flags for method attributes. These flags are defined in the corhdr.h file. |
|
MethodImplAttributes |
Specifies flags for the attributes of a method implementation. |
|
ParameterAttributes |
Defines the attributes that may be associated with a parameter. These are defined in CorHdr.h. |
|
PropertyAttributes |
Defines the attributes that may be associated with a property. These attribute values are defined in corhdr.h. |
|
ResourceAttributes |
Specifies the attributes for a manifest resource. |
|
ResourceLocation |
Specifies the resource location. |
|
TypeAttributes |
Specifies type attributes. |
Reflection Example Explanation - Listing 2.3
1: private void button3_Click(object sender, System.EventArgs e)
2: {
3: //Local variables
4: Type con = typeof(SecurityState);
5:
6: //Get Reflection values for SecurityState Class type
7: String strAssembly = con.Assembly.ToString();
8: String strAssemblyQualifiedName = con.AssemblyQualifiedName.ToString();
9: String strAttributes = con.Attributes.ToString();
10: String strBaseType = con.BaseType.ToString();
11: String strFullName = con.FullName.ToString();
12: String strGUID = con.GUID.ToString();
13: String strIsAbstract = con.IsAbstract.ToString();
14: String strIsAnsiClass = con.IsAnsiClass.ToString();
15: String strIsArray = con.IsArray.ToString();
16: String strIsAutoClass = con.IsAutoClass.ToString();
17: String strIsAutoLayout = con.IsAutoLayout.ToString();
18: String strIsByRef = con.IsByRef.ToString();
19: String strIsClass = con.IsClass.ToString();
20: String strIsComObject = con.IsCOMObject.ToString();
21: String strIsContextful = con.IsContextful.ToString();
22: String strIsEnum = con.IsEnum.ToString();
23: String strIsExplicitLayout = con.IsExplicitLayout.ToString();
24: String strIsImport = con.IsImport.ToString();
25: String strIsInterface = con.IsInterface.ToString();
26: String strIsLayoutSequential = con.IsLayoutSequential.ToString();
27: String strIsMarshalByRef = con.IsMarshalByRef.ToString();
28: String strIsNestedAssembly = con.IsNestedAssembly.ToString();
29: String strIsNestedFamilyAndAssembly = con.IsNestedFamANDAssem.ToString();
30: String strIsNestedFamily = con.IsNestedFamily.ToString();
31: String strIsNestedFamilyOrAssembly = con.IsNestedFamORAssem.ToString();
32: String strIsNestedPrivate = con.IsNestedPrivate.ToString();
33: String strIsNestedPublic = con.IsNestedPublic.ToString();
34: String strIsNotPublic = con.IsNotPublic.ToString();
35: String strIsPointer = con.IsPointer.ToString();
36: String strIsPrimitive = con.IsPrimitive.ToString();
37: String strIsPublic = con.IsPublic.ToString();
38: String strIsSealed = con.IsSealed.ToString();
39: String strIsSerializable = con.IsSerializable.ToString();
40: String strIsSpecialName = con.IsSpecialName.ToString();
41: String strIsUnicodeClass = con.IsUnicodeClass.ToString();
42: String strIsValueType = con.IsValueType.ToString();
43: String strMemberType = con.MemberType.ToString();
44: String strModule = con.Module.ToString();
45: String strName = con.Name.ToString();
46: String strNamespace = con.Namespace.ToString();
47: String strTypeHandle = con.TypeHandle.ToString();
48:
49: //Create file for writing output values
50: Stream s = File.Open("c:\\" + "SecurityStateClassReflection.txt",
FileMode.Create);
51: StreamWriter sw = new StreamWriter(s);
52:
53: //Write Reflection values to file
54: sw.WriteLine("Assembly : " + strAssembly);
55: sw.WriteLine("AssemblyQualifiedName : " + strAssemblyQualifiedName);
56: sw.WriteLine("Attributes : " + strAttributes);
57: sw.WriteLine("BaseType : " + strBaseType);
58: sw.WriteLine("FullName : " + strFullName);
59: sw.WriteLine("GUID : " + strGUID);
60: sw.WriteLine("IsAbstract : " + strIsAbstract);
61: sw.WriteLine("IsAnsiClass : " + strIsAnsiClass);
62: sw.WriteLine("IsArray : " + strIsArray);
63: sw.WriteLine("IsAutoClass : " + strIsAutoClass);
64: sw.WriteLine("IsAutoLayout : " + strIsAutoLayout);
65: sw.WriteLine("IsByRef : " + strIsByRef);
66: sw.WriteLine("IsClass : " + strIsClass);
67: sw.WriteLine("IsComObject : " + strIsComObject);
68: sw.WriteLine("IsContextful : " + strIsContextful);
69: sw.WriteLine("IsEnum : " + strIsEnum);
70: sw.WriteLine("IsExplicitLayout : " + strIsExplicitLayout);
71: sw.WriteLine("IsImport : " + strIsImport);
72: sw.WriteLine("IsInterface : " + strIsInterface);
73: sw.WriteLine("IsLayoutSequential : " + strIsLayoutSequential);
74: sw.WriteLine("IsMarshalByRef : " + strIsMarshalByRef);
75: sw.WriteLine("IsNestedAssembly : " + strIsNestedAssembly);
76: sw.WriteLine("IsNestedFamilyAndAssembly : " +
strIsNestedFamilyAndAssembly);
77: sw.WriteLine("IsNestedFamily : " + strIsNestedFamily);
78: sw.WriteLine("IsNestedFamilyOrAssembly : " +
strIsNestedFamilyOrAssembly);
79: sw.WriteLine("IsNestedPrivate : " + strIsNestedPrivate);
80: sw.WriteLine("IsNestedPublic : " + strIsNestedPublic);
81: sw.WriteLine("IsNotPublic : " + strIsNotPublic);
82: sw.WriteLine("IsPointer : " + strIsPointer);
83: sw.WriteLine("IsPrimitive : " + strIsPrimitive);
84: sw.WriteLine("IsPublic : " + strIsPublic);
85: sw.WriteLine("IsSealed : " + strIsSealed);
86: sw.WriteLine("IsSerializable : " + strIsSerializable);
87: sw.WriteLine("IsSpecialName : " + strIsSpecialName);
88: sw.WriteLine("IsUnicodeClass : " + strIsUnicodeClass);
89: sw.WriteLine("IsValueType : " + strIsValueType);
90: sw.WriteLine("MemberType : " + strMemberType);
91: sw.WriteLine("Module : " + strModule);
92: sw.WriteLine("Name : " + strName);
93: sw.WriteLine("Namespace : " + strNamespace);
94: sw.WriteLine("TypeHandle : " + strTypeHandle);
95:
96: //Close StreamWriter object
97: sw.Close();
98:
99: //Close Stream object
100: s.Close();
101: }
1: private void button3_Click(object sender, System.EventArgs e)
2: {
3: //Local variables
4: Type con = typeof(SecurityState);
The SecurityState object is a class type; therefore, line #4 retrieves the type of our SecurityState element, which is a class type, and assigns it to a variable. We will be performing reflection, determining information about our class, by using the variable "con" defined above.
7: String strAssembly = con.Assembly.ToString();
This line retrieves the name of the assembly that contains the SecurityState class. If you view Listing 2.4 below, the value retrieved is "CodeDomPartOne, Version=1.0.1045.2702, Culture=neutral, PublicKeyToken=null".
- "CodeDomPartOne" is the name of the assembly containing the SecurityState class.
- "Version" is the version number of the assembly. See the Visual Studio.NET Help Files for a full discussion of how assemblies are versioned.
- "Culture" indicates the target culture the assembly was designed for. In our case, this is set for America
- "PublicKeyToken" holds a unique identifier for our assembly, which includes security information as well. In our case, we have not secured our example with a public key. (See the discussion on "Strong Naming" and the "SN.EXE" Utility in the Visual Studio.NET Help Files for a further discussion on how to sign your assemblies with strong names.)
8: String strAssemblyQualifiedName = con.AssemblyQualifiedName.ToString();
This line retrieves the fully qualified name of the assembly that contains the SecurityState class. If you view Listing 2.4 below, the value retrieved is CodeDomPartOne.SecurityState, CodeDomPartOne, Version=1.0.1045.2702, Culture=neutral, PublicKeyToken=null".
- "CodeDomPartOne.SecurityState" is the fully qualified name of the path to the SecurityState class in our assembly. The CodeDomPartOne is the assembly name, while the SecurityState is the name of the class we are examining through reflection in our programming example.
- "CodeDomPartOne" is the name of the assembly our SecurityState class is located in.
- "Version" indicates the build version of our assembly. Versioning is a topic beyond the scope of this article. However, you might want to review the online MSDN Help Files on versioning. You will most likely have a versioning issue with your applications at some point in time.
- "Culture" determines which country culture your application is targeted toward. For example, a culture of "eng-us" indicates an English speaking culture, specifically the United States of America.
- "PublicKeyToken" holds a unique identifier for our assembly, which includes security information as well. In our case, we have not secured our example with a public key. (See the discussion on "Strong Naming" and the "SN.EXE" Utility in the Visual Studio.NET Help Files for a further discussion on how to sign your assemblies with strong names.)
9: String strAttributes = con.Attributes.ToString();
This line retrieves a list of all the available attributes associated with the type you are reflecting upon. In our example, since we are reflecting upon the SecurityState class, this line would retrieve a single attribute: the AttributeUsage attribute. If you were to view Listing 2.4 below, the values retrieved are AutoLayout, AnsiClass, NotPublic, Public, BeforeFieldInit.
10: String strBaseType = con.BaseType.ToString();
This line retrieves the type from which our current type inherits. Remember that we are building a custom attribute which MUST inherit from the System.Attribute class. Therefore, if you were to view Listing 2.4 below, the value retrieved would be System.Attribute.
- "System.Attribute" is the base class for all custom attributes you define.
11: String strFullName = con.FullName.ToString();
This line retrieves the full name of out attribute class. If you were to view Listing 2.4 below, you would see the value retrieved for our SecurityState class is CodeDomPartOne.SecurityState.
- "CodeDomPartOne" is the name of the assembly our SecurityState class is located in.
- "SecurityState" is the name of our custom attribute class.
12: String strGUID = con.GUID.ToString();
This line sets the value of the GUID associated with the type. A GUID is a globally unique identifier, which distinguishes one type from another. If you were to view Listing 2.4 below, you would see the value retrieved for our SecurityState class is 39c134a5-c237-3392-b345-d5a62c5573b1.
13: String strIsAbstract = con.IsAbstract.ToString();
This line retrieves the setting indicating if the type must be overridden. If a type must be overridden, that type is labeled as being abstract. Since we did not specify that our SecurityState attribute class must be overridden with another implementation, the value of the IsAbstract property for the SecurityState class is False. You can view this in Listing 2.4 below.
14: String strIsAnsiClass = con.IsAnsiClass.ToString();
This line retrieves the setting indicating if the value of strings should be formatted as ANSI strings. If you view Listing 2.4 below, you will see the value for this property for the SecurityState class is True.
15: String strIsArray = con.IsArray.ToString();
This line retrieves the setting indicating whether the SecurityState class happens to be an array - which of course it is not. This property would return true if this class were a collection of other similarly grouped objects. If you look at Listing 2.4 below, you will see the value of the IsArray property is False.
16: String strIsAutoClass = con.IsAutoClass.ToString();
This line retrieves the setting for the AutoClass attribute for the SecurityState class. The AutoClass attribute indicates that strings will be interpreted not as ANSI strings by default, but by some other interpreting scheme automatically. If you look at Listing 2.4 below, you will see the value of the IsAutoClass property is False. It is important to realize that strings and characters appear differently, and are interpreted differently in different parts of the world. Not everyone uses an ANSI character or string encoding by default; therefore, it may be important to your application to be aware of how to display strings to the user.
17: String strIsAutoLayout = con.IsAutoLayout.ToString();
This line retrieves the setting for the IsAutoLayout property for the SecurityState attribute class. The IsAutoLayout property indicates the fields appearing in the SecurityState class should be laid out automatically by the Common Language Runtime (CLR). If you look at Listing 2.4 below, you see the value of the IsAutoLayout property is True.
18: String strIsByRef = con.IsByRef.ToString();
This line retrieves the setting for the IsByRef property for the SecurityState class. The IsByRef property indicates whether or not the type you are reflecting on was passed by reference to another routine. If you look at Listing 2.4 below, you will see that the value for our SecurityState class is False. This is mostly because we placed the definition of our attribute class inside the same assembly we are reflecting upon. However, if you changed the constructor list for the SecurityState class, you may find this value changes.
19: String strIsClass = con.IsClass.ToString();
This line retrieves the setting for the IsClass property for the SecurityState class. The IsClass property indicates if the type we are reflecting upon is a class element. For this property to be evaluated as true, the type being reflected upon may not be a value type or an interface type. If you look at Listing 2.4 below, you will see the value of the IsClass property for our SecurityState class type is True. This is because when you define a custom attribute, the attribute must be a class that derives from the System.Attribute class.
20: String strIsComObject = con.IsCOMObject.ToString();
This line retrieves the setting for the IsCOMObject property for the SecurityState class. The IsCOMObject property indicates if the type we are reflecting upon is a COM object. For our SecurityState class the type we are reflecting against is a class type; therefore, the SecurityState class is not a COMObject type. If you look at Listing 2.4 below, you will see the value for our SecurityState class type is False.
21: String strIsContextful = con.IsContextful.ToString();
This line retrieves the setting for the IsContextful property for the type we are reflecting upon - our SecurityState class. When a class member is called, that class member can have what is called a "context" wrapped around it. The context is responsible for intercepting calls to class members and for enforcing synchronization and security policies. If you look at
Listing 2.4 below, you will see the value for the type we are reflecting upon, the SecurityState class, is False. This means that method calls are not intercepted before they are processed by the member methods.
22: String strIsEnum = con.IsEnum.ToString();
This line retrieves the setting for the IsEnum property for the type we are reflecting upon - our SecurityState class. The IsEnum property indicates if the current type being reflected upon is an enumeration. In our case, the value of the IsEnum property will be false because our SecurityState attribute is a class type that inherits from the System.Attribute class. If you look at Listing 2.4 below, you will see the value for the type we are reflecting upon, the SecurityState class, is False.
23: String strIsExplicitLayout = con.IsExplicitLayout.ToString();
This line retrieves the setting for the IsExplicitLayout property for the type we are reflecting upon - our SecurityState class. The IsExplicitLayout property determines how the Common Language Runtime (CLR) lays out the member fields of your class in memory. When the value of this property is set to True, the member fields of the type being reflected upon must be specifically configured to load each one into memory using the Common Language Runtime (CLR). In our case, we do not care how the CLR lays out our fields in memory so the value of the IsExplicitLayout property should be false. If you look at Listing 2.4 below, you will see the value for the type we are reflecting upon, the SecurityState class, is False.
24: String strIsImport = con.IsImport.ToString();
This line retrieves the setting for the IsImport property for the type we are reflecting upon - our SecurityState class. The IsImport property determines if the current type being reflected upon was imported from another type. In other words, did we use the "Imports" or "using" directives to gain access to the current type being evaluated? Since we did not reference the SecurityState class from another type, the value for this property, as listed in Listing 2.4 below, is False.
25: String strIsInterface = con.IsInterface.ToString();
This line retrieves the setting for the IsInterface property for the type we are reflecting upon - our SecurityState class. The IsInterface property determines that the type we are reflecting upon is not a class or a value type, but is defined as an interface. Since the type of element we are reflecting upon is a class (SecurityState class), the value if the IsInterface property in our example is False. If you look at Listing 2.4 below, you will see the value in our example is indeed False.
26: String strIsLayoutSequential = con.IsLayoutSequential.ToString();
This line retrieves the setting of the IsLayoutSequential property for the type we are reflecting upon - our SecurityState class. The IsLayoutSequential property is used by the Common Language Runtime (CLR) to arrange the fields of a class in memory. This property ensures there is proper empty memory space between fields. If you look at Listing 2.4 below, you will see the value for our SecurityState class is False.
27: String strIsMarshalByRef = con.IsMarshalByRef.ToString();
This line retrieves the setting of the IsMarshalByRef property for the type we are reflecting upon - the SecurityState class. The IsMarshalByRef property indicates if the type being reflected upon was sent across the wire by reference. Our SecurityState class type did not arrive by reference so the value of the IsMarshalByRef property is False. If you look at Listing 2.4 below, you will see the value for our SecurityState class is False.
28: String strIsNestedAssembly = con.IsNestedAssembly.ToString();
This line retrieves the setting of the IsNestedAssembly property for the type we are reflecting upon - the SecurityState class. The IsNestedAssembly property indicates if the current assembly is contained, or nested, within another assembly. If so, the assembly in question will be visible only within the assembly it is defined. Since we did not define our SecurityState class inside another class or assembly, the value of the IsNestedAssembly clas is False. If you look at Listing 2.4 below, you will see that the value of the IsNestedAssembly property is indeed False.
29: String strIsNestedFamilyAndAssembly = con.IsNestedFamANDAssem.ToString();
This line retrieves the setting of the IsNestedFamilyAndAssembly property for the type we are reflecting upon - the SecurityState class. The IsNestedFamilyAndAssembly property indicates if the type is nested and is visible only to classes that belong to the group or family or its own assembly. The value of the IsNestedFamANDAssem property will be False. We did not nest our SecurityState class inside another class. If you look at Listing 2.4 below, you will see that the value of the IsNestedFamANDAssem property is False.
30: String strIsNestedFamily = con.IsNestedFamily.ToString();
This line retrieves the setting of the IsNestedFamily property for the type we are reflecting upon - the SecurityState class. The IsNestedFamily property indicates if the type is nested and is visible only within its own assembly. In our case, the SecurityState class is not a nested class and is public in scope - therefore, it is visible to other assemblies outside our own and is not a nested class. (i.e. a class containing other classes.) If you look at Listing 2.4 below, you will see that the value of the IsNestedFamily property is False.
31: String strIsNestedFamilyOrAssembly = con.IsNestedFamORAssem.ToString();
This line retrieves the setting of the IsNestedFamORAssem property for the type we are reflecting upon - the SecurityState class. The isNestedFamORAssem property indicates if the type is visible only to classes that belong to either its own family of classes or its own assembly. In our case, the SecurityState class satisfies all the criteria of this property except one - the SecurityState class is not a nested class (i.e. a class contained within another class). If you look at Listing 2.4 below, you will see the value of the IsNestedFamilyOrAssembly is False.
32: String strIsNestedPrivate = con.IsNestedPrivate.ToString();
This line retrieves the setting of the IsNestedPrivate property for the type we are reflecting upon - the SecurityState class. The IsNestedPrivate property determines two things: if the type is a nested class (contained withi |