Component based technology has done great things for software development, allowing reuse and leading to better-written code that separates subjects and entities into distinct components. One of the potential side effects of working with components, however, is that at times we find ourselves faced with a dll assembly that contains several classes where only the method names are documented. This is especially true in poorly documented libraries, with classes that implement well known interfaces. Luckily, the System.Reflection namespace of the .Net framework arms us with enough functionality to overcome this problem.
The Assembly class
The System.Reflection.Assembly class provides us with the functionality needed to probe into what the assembly has to offer. In this case, our plan is to load the assembly of interest into our application domain, and then query for all the types included in it. We can loop through all the types, finding out whether the method that we are interested in is a member of any of those types.
Once the method is found, we create an instance of the type that contains the method and invoke that method.
Querying types in an assembly
Let us assume that we are interested in calling a mthod from an assembly named SomeControls.dll, that we have it stored locally in C:\AssemblyDir. The method we need to call is named GetUserName, with the following signature:
string GetUserName(string account)
The first thing we need to do is to load the assembly, using the file name of the dll:
Assembly assemblyInstance = Assembly.LoadFrom(@"c:\AssemblyDir\SomeControls.dll");
After we get an instance of the loaded assembly, we can call the GetTypes() method of the Assembly class to get an array containing all the types defined in the asembly:
Type[] types = assemblyInstance.GetTypes();
Once we get an array containing all the types in the assembly, we can loop through and look for the method in each type. The GetMethod(string) member method of the Type class returns a MethodInfo object if the method happens to be a member of that type, and null if not found:
foreach (Type t in types)
{
MethodInfo mi = t.GetMethod(GetUserName);
Creating a type instance
Once the method is found in one of the types, We create an instance of that type so that we can call its method. We have two options for creating an instance of a type: using Reflection or using the Activator class of the System namespace.
To use reflection, we need to call the CreateInstance(string) instance method of the Assembly class, which takes the type name as an argument.
If we use the Activator class, we have to call its CreateInstance(Type) static method, which takes the type object as an argument.
Invoking the method
Once we have an instance of the type containing the method, the final step is to call the InvokeMember() method of the Type class, passing in the instance of the type and the Account string argument.
The code below shows all the steps described so far:
MethodInfo mi;
object result = null;
object[] args = new object[] {"ABC123"};
try
{
Assembly assemblyInstance = Assembly.LoadFrom(@"c:\AssemblyDir\SomeControls.dll");
Type[] types = assemblyInstance.GetTypes();
foreach (Type t in types)
{
mi = t.GetMethod("GetUserName");
if (mi != null)
{
string typeName = t.FullName;
object lateBoundObj = Asm.CreateInstance(typeName);
result = t.InvokeMember (MethodName, BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, lateBoundObj, args);
break;
}
}
string userName = result.ToString();
MessageBox("User Name is: {0}", userName)
}
catch(Exception ex)
{
MessageBox.Show(ex.Message)
}