Introduction to Reflection
Discover how to use reflection in C# to inspect and obtain metadata about types, members, and assemblies at runtime.
We'll cover the following...
Every application is composed of classes and other types, along with their methods, properties, and indexers. Reflection lets us obtain type information while the program is running. For instance, we could discover what methods a class has, what properties it operates, and what interfaces it implements. Reflection is type discovery at runtime.
The reflective functionality of .NET is located in the System.Reflection namespace. To obtain information on a type, we use the System.Type class. This class has methods like:
GetMembers(): This returns aMemberInfo[]object.GetConstructors(): This returns aConstructorInfo[]object.GetMethods(): This returns information onMethodInfo[]methods.
While the Type class exposes many members, these methods provide a general idea of its capabilities.
Obtain type information
To obtain information on a type, we must first get an instance of the Type class representing that type. We can do that in three ways:
Use the
typeofoperator.Call
GetType()on an instance of the type we are interested in.Call the static
Type.GetType()method and provide the fully qualified name of the type.
The following code shows all three ways to obtain type information:
Line 2: We use the
typeofoperator to get the type information of the built-ininttype.Line 7: We call the
GetType()method on an instantiated string object to retrieve its type.Line 11: We use the static
Type.GetType()method, passing the fully qualified name of the type as a string. We use the nullableType?because this method returnsnullif the requested type cannot be found.
Properties of the Type class
The Type class has properties that allow us to learn more about the type:
Name: The type’s name.Namespace: The namespace where the type is defined.BaseType: A parent type this type inherits from.IsArray: This returns true if the type is an array type.IsClass: This returns true if the type is a class.IsEnum: This returns true if the type is an enumeration.IsInterface: This returns true if the type is an interface.IsValueType: This returns true if the type is a struct.
Now, let’s explore the System.String type by accessing the Type object’s properties:
Line 1: We obtain the
Typeobject for thestringclass.Lines 3–7: We access various properties of the
Typeobject to print the string’s name, full name, namespace, base type, and whether it is a class.
The information shown in the output of the code above can be obtained on user-defined and third-party types as well.
Additional classes
The System.Reflection namespace also contains the following set of classes:
Assembly: This represents the program assembly and allows developers to interact with it.AssemblyName: This contains information on the assembly.MemberInfo: This is a base abstract class for types that contain information on a method, property, event, and field. For each member, there is a corresponding sub-class (MethodInfo,PropertyInfo,FieldInfo).ConstructorInfo: This contains information about a constructor.
These classes represent the basic building blocks of any .NET application. Compiling a project produces an assembly containing types, which are further composed of members.
Let’s inspect the string class further and learn more about the assembly it is located in:
Line 1: We import the
System.Reflectionnamespace, which provides classes for inspecting assemblies and metadata.Line 3: We get the
Typeinformation for thestringclass.Line 5: We retrieve the
Assemblyobject where thestringtype is defined.Line 6: We get the
AssemblyNameobject, which contains detailed metadata about the assembly.Lines 8–9: We print the assembly’s name and version to the console.
We can also explore our own project. Even when using top-level statements, the compiler implicitly generates an internal Program class for us behind the scenes, which we can inspect:
Line 4: We obtain the
Typeinformation for our auto-generatedProgramclass.Lines 6–7: We retrieve the
AssemblyandAssemblyNameobjects associated with our current executing project.Lines 9–10: We output the name and version of our custom assembly.