How Reflection Works
The most fundamental .NET Framework class used in reflection is the Type class. This abstract class allows you to access a type's metadata. Although the Type class is defined in the System namespace rather than the System::Reflection namespace, it is actually the gateway to all reflection capabilities. Other reflection-related classes reside in the System::Reflection namespace. The Type class encapsulates type information of a class, interface, array, value, or enumeration declared within managed code, written in any .NET language. It is also significant that the Object class, which is the root of the entire .NET type hierarchy, supports the GetType method, which gives you a Type object from an instance of any type.
Type* Object::GetType()
As an alternative to the Object::GetType method, you can apply the __typeof operator, which is a managed extension for C++, to determine the Type object associated with any object or expression. However, __typeof is a bit more flexible than the Object::GetType method: It can take an abstract declarator as an argument, which means that you do not require an object to be instantiated to obtain a Type.
Many methods and properties exist in the Type class, and you can view them in the documentation. However, I'll look into a few obviously interesting ones.
You can get the type associated with a specified type name with the static GetType method:
Type* Type::GetType(String* typeName)
You can get the attributes associated with a type with the Attributes property:
TypeAttributes Type::get_Attributes()
You can get the base type from which a derived type inherits with the BaseType property:
Type* Type::get_BaseType()
You can get the methods of a type with the GetMethods method:
MethodInfo* Type::GetMethods() []
You can get the fields of a type with the GetFields method:
FieldInfo* Type::GetFields() []
You can get the properties of a type with the GetProperties method:
PropertyInfo* Type::GetProperties() []
You can get the events of a type with the GetEvents method:
EventInfo* Type::GetEvents() []
To reflect on a particular type, you need to load the assembly that contains the type that you are interested in. If the type happens to be in one of the program's own assemblies, this requirement is automatically satisfied. If the type is defined in an external assembly, the program must load that assembly explicitly. The .NET Framework provides the Assembly class, which encapsulates information and functionality related to a .NET assembly. Recall that an assembly contains compiled code and metadata that describes that code. Loading an external assembly can be accomplished using the static Assembly::LoadFrom method:
Assembly* Assembly::LoadFrom(String* assemblyFile)
There are some other interesting properties and methods of the Assembly class as well. The FullName property gets the display name of an assembly:
String* Assembly::get_FullName()
The GetCustomAttributes method gets the attributes that apply to the assembly as a whole:
Object* Assembly::GetCustomAttributes(bool inherit) []
The GetTypes method gets the types defined within an assembly:
Type* Assembly::GetTypes() []
All attribute classes are derived from the System::Attribute class. After you have obtained the array of Attribute-derived objects using the Assembly::GetCustomAttributes method, you can inspect each one to see if it matches a particular attribute that you are interested in. For example, you can call GetType on each attribute object and compare it to known attribute-derived types, such as AssemblyCopyrightAttribute, AssemblyCompanyAttribute, and so forth. In this way, you can determine what attributes are applied to the assembly as a whole.
When you have obtained an array of Type objects, by calling Assembly::GetTypes, you can proceed to reflect on each of the types in the assembly. You can then work with the classes in the System::Reflect namespace, such as MethodInfo, FieldInfo, ParameterInfo, and so forth, to dive into the details of each type found in the assembly.
The MethodInfo class, which is derived from MethodBase, provides access to the attributes of a method and provides access to method metadata. As previously mentioned, an array of MethodInfo objects is obtained by calling the Type::GetMethods method. The MethodInfo class provides several properties for analyzing the details of a method, including the method attributes, the method return type, and the method name.
The Attributes property provides a bit flag enumeration named MethodAttributes, indicating whether the method is abstract, public, private, static, virtual, and so forth:
MethodBase::MethodAttributes MethodBase::get_Attributes()
The ReturnType property provides the type of the method's return value:
Type* MethodBase::get_ReturnType()
The Name property provides the String representation containing the name of the method:
String* MemberInfo::get_Name()
The GetParameters method provides an array of ParameterInfo objects that allow you to drill down farther to get to the metadata of each method parameter:
ParameterInfo* MethodInfo::GetParameters() []
When you have access to the method parameters, you can drill down farther. The ParameterInfo class provides access to the attributes of a parameter and also provides access to parameter metadata. This class provides methods and properties for accessing the parameter's attributes, name, and position, as well as determining whether the parameter is optional, in, out, retval, and so forth.
The Attributes property provides the attributes that are applied to the parameter:
ParameterAttributes ParameterInfo::get_Attributes()
The Name property provides the String representation that contains the name of the parameter:
String* ParameterInfo::get_Name()
The ParameterType property provides the data type of the parameter:
Type* ParameterInfo::get_ParameterType()
Just as you can reflect on the methods and method parameters of a type using MethodInfo and ParameterInfo, you can reflect on the constructors, events, fields and properties of a type. The System::Reflect namespace provides the following classes for these purposes: ConstructorInfo, EventInfo, FieldInfo, and PropertyInfo. This article does not go further into these additional classes because they are quite similar in concept to what we have already described for the MethodInfo and ParameterInfo classes. The code example, however, does show these additional classes in action. For further information on these additional classes, read through the example code provided for this article and the documentation for each of these classes.