Reflection has always been considered an 'advanced' topic in most programming books, probably because you seldom use it unless you are in the business of writing debuggers and introspection tools such as the Javabean Development Kit. I myself would try to avoid using reflection as much as possible if there are alternative ways to do things.
This particular chapter has been written in a very 'dry' style. I have simply included lots of short code examples showing how to perform certain reflection operations using reflection classes in the BCL. The intention is that you can refer back here when there is a need to write reflection codes. Like Java, reflection is largely dependent on the class libraries provided. There are no new C# keywords to be learnt in this chapter – all you have to do is to become familiar with the C# reflection API. You could skip this chapter altogether and come back when you need 'how-to' reflection examples quickly.
Reflection is possible in C# because the metadata stored, together with IL codes, in a .NET assembly provides information about the assembly itself.
Most of the classes related to reflection operations are in the following namespaces: System.Reflection and System.Reflection.Emit. They are listed in Tables 16.1 and 16.2.
Namespace | Description |
---|---|
System.Reflection | Contains classes/interfaces that provide a managed view of loaded types, methods and fields with the ability to dynamically create and invoke types |
System.Reflection.Emit | Contains classes that allow a compiler or tool to emit metadata and IL codes, and optionally generate an assembly file on disk – script engines and compilers will use classes of this namespace |
System.Type is the most important class here. Type is an abstract base class that represents a type in the CTS – which can be a class or interface.
From the view-of-classes shown in Figure 16.1, I have extracted those classes which represent different entities in C# – these are shown in Figure 16.2.
Class | Description |
---|---|
System namespace | |
Type | Represents type declaration (class types, interface types, array types, value types, enum types) |
Activator | Contains methods to create types of objects locally or remotely, or obtain references to existing remote objects |
AppDomain | Represents an application domain – an application domain is an isolated environment where applications execute within. Application domains are also separated by security boundaries for executing managed code |
System.Reflection namespace | |
Assembly | Represents an assembly – an assembly is a reusable and self-describing block of .NET codes which can be versioned |
Module | Represents a module, and contains methods which permit reflection on a module – an assembly can consist of multiple modules |
PropertyInfo | Discovers the attributes of a property and provides access to property metadata |
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 |
MethodInfo | Discovers the attributes of a method and provides access to method metadata |
System.Reflection.Emit namespace | |
AssemblyBuilder | Defines and represents a dynamic assembly |
ModuleBuilder | Defines and represents a module |
PropertyBuilder | Defines the properties for a type |
EventBuilder | Defines events for a class |
FieldBuilder | Defines and represents a field |
ILGenerator | Generates IL codes |
An AppDomain object is the root of the type hierarchy of a .NET application during runtime. The AppDomain class represents a .NET application domain which is similar to a Win32 process. You can have multiple .NET assemblies executing in separate application domains simultaneously. A .NET assembly can contain one or more modules. Each module contains one or more Types (classes, interfaces) and, of course, you can find properties, events, fields, and methods within a Type.
In the following sections, I shall show how to perform various reflection tasks. If you follow the code examples given, performing reflection operations in C# should be straightforward.
3.146.35.72