February 17th, 2009
Exploring C# reflection - 1

In this post I look at how we can simply retrieve basic information about our own types, discover their methods and lastly how we can import a foreign assembly, inspect its contents, load a class and execute its methods.
When C# compiles your code it not only stores the program in the assembly but the complete information on each of the structures you have defined. Each class, its types, parameters and methods described into detail are all available. This might sound like stating the obvious, but until recently most compilers treated this kind of “meta” data as a waste of space and never included it into the final assembly.
Through reflection C# offers a way of inspecting this meta information from a running program. The program reflects on itself to discover itself. It can use this to change the way it runs, or to report the results back to the user.
Why is this useful? If you distribute an application that accepts third plug-ins you need some kind of mechanism to inspect whether the supplied plug-in provides the correct set of methods for your code to work with. Very similar to how Visual Studio works with plug-ins.
Type
To be able to interact with their own code C# programs rely heavily on the Type class. The Type class can represent all C# type declarations: class types, interface types, array types, value types, enumeration types, type parameters etc. You can use it to query a type and discover what kind of contents it has.
GetType() is the most common way to access C# reflection and I’ll show in the next example how you can find out the original type of an object after it has been cast down to a basic object. The GetType() method is inherited from object, so each C# object has access to it. As can be expected, GetType() returns an instance of the Type class.
But first have a look a simple example of how we can use GetType()
using System;
using System.Reflection;
class MainClass
{
// This routine takes an object, which is the root of all
// types in C#
public static void PrintType(object Data)
{
Console.WriteLine("Type of Data: {0}",Data.GetType());
}
public static void Main(string[] args)
{
string msg = "Hello World";
PrintType(msg);
int theValue = 1024;
PrintType(theValue);
}
}
This will print:
Type of Data: System.String
Type of Data: System.Int32
If you know that the object you were passed was really a System.Int32 object, you can could cast it back and modify it as a regular integer. The following works but isn’t very nice:
object Test = new int();
// This only works if the above object is an integer
if (Test.GetType().ToString()=="System.Int32")
{
int MyInt = (System.Int32) Test;
MyInt = 20;
}
A much better way of course in your own code to do the following:
object Test = new int();
if (Test is int)
{
int MyInt = (int) Test;
MyInt = 20;
}
The TypeOf operator
The typeof() operator works in similar fashion at GetType but on type definitions at compile time. The GetType() operator works on instances of variables and is available at run-time. The benefit is that you don’t have to instantiate a class to obtain an type instance. To illustrate the difference have a look at the following:
Type e = typeof(MyExampleClass); // This is the same as: MyClass example = new MyExampleClass(); Type t = example.GetType();
Using Type to query a class methods and members
Of course we can obtain much more information about a class than just its name. We can use the GetMethods() method to obtain a list of all the methods in the class, and GetMembers() to obtain all its member variables. Not only that, we can also call these members after we discover them.
using System;
using System.Reflection;
namespace Reflection
{
class MySecretClass
{
public int Z;
public int Add(int x) { return x+1; }
public int Sub(int x) { return x-1; }
MySecretClass()
{
Z = 0;
}
}
class MainClass
{
public static void Main(string[] args)
{
Type t = typeof(MySecretClass);
MethodInfo[] MethodArray = t.GetMethods();
foreach (MethodInfo Method in MethodArray)
Console.WriteLine("Method: {0}",Method.ToString());
MemberInfo[] MemberArray = t.GetMembers();
foreach (MemberInfo Member in MemberArray)
Console.WriteLine("Member: {0}",Member.ToString());
}
}
}
Loading an external assembly
Inspecting our own types is not nearly as adventurous as trying to decode the definitions found in a assembly you are trying to understand or validate. The following code loads the “mscorlib.dll” (which is the present in all .NET environments) and prints its name, version, culture and public key:
System.Reflection.Assembly LoadedAssembly = System.Reflection.Assembly.Load("mscorlib.dll");
System.Console.WriteLine(LoadedAssembly.GetName());
We can query the assembly for a couple of basic variables, such as its name, location etc:
Console.WriteLine("Full Name: {0}", LoadedAssembly.FullName);
Console.WriteLine("Location: {0}", LoadedAssembly.Location);
Console.WriteLine("Code Base: {0}", LoadedAssembly.CodeBase);
Console.WriteLine("Escaped Code Base: {0}", LoadedAssembly.EscapedCodeBase);
Console.WriteLine("Loaded from GAC: {0}", LoadedAssembly.GlobalAssemblyCache);
Now the assembly is in memory we can explore it using the above introduced Type class, the GetTypes() method returns an array of all types in the assembly. The full code that queries the mscorlib.dll in detail is below:
using System;
using System.Reflection;
namespace Reflection
{
class MainClass
{
public static void Main(string[] args)
{
System.Reflection.Assembly LoadedAssembly = System.Reflection.Assembly.Load("mscorlib.dll");
System.Console.WriteLine(LoadedAssembly.GetName());
Console.WriteLine("Full Name: {0}", LoadedAssembly.FullName);
Console.WriteLine("Location: {0}", LoadedAssembly.Location);
Console.WriteLine("Code Base: {0}", LoadedAssembly.CodeBase);
Console.WriteLine("Escaped Code Base: {0}", LoadedAssembly.EscapedCodeBase);
Console.WriteLine("Loaded from GAC: {0}", LoadedAssembly.GlobalAssemblyCache);
Type[] types = LoadedAssembly.GetTypes();
foreach (Type t in types)
{
Console.WriteLine ("Name: {0}", t.FullName);
Console.WriteLine ("Namespace: {0}", t.Namespace);
}
}
}
}
Calling dynamically bound assemblies at runtime
After we have loaded an assembly we want to execute some code in it. In the above example we used the mscorelib.dll because it conveniently is available on all .NET systems. In the following example I show how you can create an object instance and call a named method.
The System.DateTime class is one of many stored in this dll, and we are interested in the ToLongDateString method. Normally we would call it in a manner similar to the below:
System.DateTime myTime = new System.DateTime(2000,1,1,12,0,0);
Console.WriteLine("Current Time: {0}",myTime.ToLongDateString());
As we have loaded mscorlib dynamically we need to go through some more steps to locate the method and constructor we are interested in:
object myObject = LoadedAssembly.CreateInstance("System.DateTime",false,BindingFlags.ExactBinding,null,new Object[] {2000,1,1,12,0,0},null,null);
We use CreateInstance to create an instance of the class we require, “System.DateTime”. Just ignore the other parameters for now; the second important one is where we pass an object array containing the exact number of variables to match the correct constructor.
Next we need to obtain a handle to the method inside the class we want to invoke.
MethodInfo m = LoadedAssembly.GetType("System.DateTime").GetMethod("ToLongDateString");
We execute the method by calling “Invoke”, passing our object and an object array of parameters (null as ToLongDateString does not take any). We need to cast the resulting object to a string.
string result = (string) m.Invoke(myObject,null);
Console.WriteLine("The time and date: {0}",result);
From the above it is clear that calling methods from a dynamically loaded and bound assembly is considerably more work. It does however allow you to extend your program through third party extensions, or by enabling functionality through assemblies that might not be available on all systems.
The full code for the final example is below:
using System;
using System.Reflection;
namespace Reflection
{
class MainClass
{
public static void Main(string[] args)
{
System.Reflection.Assembly LoadedAssembly = System.Reflection.Assembly.Load("mscorlib.dll");
System.Console.WriteLine(LoadedAssembly.GetName());
// Doing it the statically bound way
System.DateTime myTime = new System.DateTime(2000,1,1,12,0,0);
Console.WriteLine("Current Time: {0}",myTime.ToLongDateString());
// And now through an assembly loaded at runtime
object myObject = LoadedAssembly.CreateInstance("System.DateTime",false,BindingFlags.ExactBinding,null,new Object[] {2000,1,1,12,0,0},null,null);
MethodInfo m = LoadedAssembly.GetType("System.DateTime").GetMethod("ToLongDateString");
string result = (string) m.Invoke(myObject,null);
Console.WriteLine("The time and date: {0}",result);
}
}
}
Image credit: Mike Baird
Tags: c#, reflection









Except where otherwise noted, content on this site is
October 20th, 2009 at 4:23 pm
hi – great article,
is there anyway to expand your: Console.WriteLine(“Member: {0}”, Member.ToString());
to get the parameter name in addition to the parameter type?
for example, knowing the name resultName and resultId would be very helpfull from the below example.
Method: System.String object GetResultNames(ref string resultName, int resultId)
i am loading using the following technique:
Assembly dll_;
dll_ = Assembly.LoadFile(“C:\\Settings\\ReflectMethods\\Debug\\Interop.ExcelLib.dll”);
interface_name_ = “ILQ”;
foreach (Type t in dll_.GetTypes())
…………….
MemberInfo[] MemberArray = t.GetMembers();
…………….
thanks in advance