The meaning of reflection is to provide information on an assembly, type, a method, a constructor or an interface implemented. Every time you run the .NET Reflector, or simply use the dot syntax to explore the members of a class by Intellisense, you use reflection.
Reflection is particularly useful when you have no compile time knowledge of a given type (let’s say for example when you want to create an extendable application). To implement and load a snap-in, you’d create a method which checks for an assembly (the snap-in itself). You’d mark the classes with attributes, or even better, implement a predefined interface (which this time will really act as a contract). What you’d do is the following:
- Create a Class Library (e.g.: Commons.dll), and define your interface there.
- Create your main application, and set a reference on the Commons.dll
- Create a method which checks for the implemented contract interface in a given assembly (or in a group of assemblies, for example in the \AppPathSnapIns directory.
- Create some snap-ins, set a reference on the Commons.dll, and create classes which implements it.
- Run your application.
I think the only thing which needs explanation is the checking for the implemented interface in an assembly you haven’t added reference at compile time. This is exactly something which needs reflection. How would you do it?
Assembly assem = Assembly.LoadFrom(@”C:AppPathSnapInssnapin.dll”);
foreach(Type t in assem.GetTypes())
if(t.GetInterface(“ISnapIn”) != null)
This method prints all classes which implements the ISnapIn interface. For example, you could create an instance of a type (using late-binding) instead of simply print out its name by creating an object instance, and the call:
Object o = Activator.CreateInstance(t);
If you’d like to call a method (with no parameters) you could use the following syntax:
MethodInfo mi = t.GetMethod(“SomeMethod”);
If you’d got some parameters, you’d simply create an object array with them, and pass it to the Invoke method instead of just passing null.
As you could have seen, the main classes here are Type, Assembly and Activator. Type has a massive number of methods, the most interesting is GetType, which returns a type reference from a string. It has three constructor overloads:
- String TypeName
- String TypeName, Boolean ThrowError
- String TypeName, Boolean ThrowError, Boolean IgnoreCase
When you’ve acquired a type reference, you could easily create an instance of it by using the static methods of Activator. Activator.CreateInstance is a such method. It returns an object, and needs a simple Type parameter, in its simplest form. You should understand that to be able to call instance methods, you’d need an instance (in this case, a late-bound one) of the class. You should pass this instance whenever you request a method invoke, need a property, etc.
The Assembly class has the ability to load an assembly in reflection-only or normal mode. Reflection-only mode means that you cannot call methods or create instances of classes, just examine them. When you need an assembly form the GAC, you should call Assembly.Load, when needing to load from a file path, use the Assembly.LoadFrom method.
There are a number of assembly attributes which you should be familiar with. They have very describing names, and you can meet them if you open your AssemblyInfo.cs file. They have the prefix of assembly: