Chapter 16. Reflection and dynamic method invocation
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.
Table 16.1. Description of the namespaces which contain significant classes for reflection
Contains classes/interfaces that provide a managed view of loaded types, methods and fields with the ability to dynamically create and invoke types
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.
Figure 16.1. Classes which are significant in reflection. S.R. stands for the System.Reflection namespace; and S.R.E. stands for the System.Reflection.Emit namespace. Classes in unshaded boxes are found in the System namespace.
Figure 16.2. Classes which represent.NET entities.
Table 16.2. Description of the significant classes for reflection
Represents type declaration (class types, interface types, array types, value types, enum types)
Contains methods to create types of objects locally or remotely, or obtain references to existing remote objects
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
Represents an assembly ?an assembly is a reusable and self-describing block of .NET codes which can be versioned
Represents a module, and contains methods which permit reflection on a module ?an assembly can consist of multiple modules
Discovers the attributes of a property and provides access to property metadata
Discovers the attributes of an event and provides access to event metadata
Discovers the attributes of a field and provides access to field metadata
Discovers the attributes of a method and provides access to method metadata
Defines and represents a dynamic assembly
Defines and represents a module
Defines the properties for a type
Defines events for a class
Defines and represents a field
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.