The first example with be the simplest and most straightforward. We'll invoke a method that takes no parameters and returns a string. What is as simple as string s = obj.Method();
takes quite a few extra steps when using reflection.
- Load an assembly from a known Data Link Libarary (DLL) in a known location
- Create a System.Type object of the class of the object you want to instantiate
- Create an instance of the class object
- Create a System.Reflection.MethodInfo object that represents the method we will invoke
- Invoke the method within the object we created
- Cast the generic object returned to its proper type
Okay, there was a lot of jargon in there and I assure you I'll try to explain each step in a straightforward manner. I've tried to use correct terms in all cases above because these are standard object-oriented terms that all software developers should be familiar with. Used correctly and consistently, they will aid communication rather than hinder it.
If you're not familiar with these terms, stay with me -- perhaps they'll become clearer as we walk through this process.
Load the Assembly
System.Reflection.Assembly assem =
System.Reflection.Assembly.LoadFrom(@"c:\path\to\file.dll");
First, we need to find and load the DLL that has the great functionality we're going to invoke. I would wrap this in a try/catch block and provide error processing when the DLL isn't where we expect it.
Create a System.Type object
We're used to creating C# objects this way:
System.Text.StringBuilder sb = new System.Text.StringBuilder();
In this example, sb
is the object instantiation of typeStringBuilder
.
In other words, sb
is a StringBuilder
object; an instantiation of classStringBuilder
. These phrases tell us that somewhere there is something called a StringBuilder
class, and the code above created an object of that type.
The object that we will create through reflection also has a class type, ClsX. The compiler is able to recognize many types of objects such as System.Text.StringBuilder
but is clueless about the class of object we want. We will need to create a Type
object to represent that class type.
System.Type typClsX = assem.GetType("Fully.Qual.ClsX",true);
Where did that "Fully.Qual" thing come from? That is called a namespace. The C# code that created the target DLL probably resembled this:
namespace Fully.Qual
{
public class ClsX {
//properties and methods for ClsX
}
}
Always wondered what the deal was with those namespaces, huh? Here's one place we use them.
We want to be sure that we are targeting the "right" ClsX
and not some other ClsX
in some other namespace, so we need to specify the fully qualified namespace for the ClsX
we are targeting. C# is picky that way.
The second parameter in the GetType
method, specified as true
indicates that you want to throw an error if there is a problem loading the DLL.
Now that we have an object representing the type of object being targeted, we can now actually create one of those objects.
Instantiate a Target Object
The method we are after is not static, so we must first create an object of type ClsX
, then invoke a method on the instantiated object. So far, we've loaded the assembly, and gathered information about ClsX into a System.Type object, typClsX
. Now we're going to perform the equivalent of new Fully.Qual.ClsX()
.
object oClsX = System.Activator.CreateInstance(typClsX);
typClsX
has enough information inside it to generate an object of type ClsX. System memory is allocated and the default class constructor is called to populate any internal properties.
Once an object of type clsX
is created, we can call on all the public methods within that class object.
Instantiate a MethodInfo Object
To call a method in a class object, we'll need to locate it specifically. Didn't we already do that? you may be asking yourself. In a word no. We have a class object ClsX
and it may have several public methods within it. Some may even have the same name but take different parameters.
We'll now create an object to represent that unique method we're after. We must specify the method signature: its name and parameter information.
We have no parameters to pass in this example, so we will indicate "no parameters" by supplying a zero-sized Type array to the method call.
System.Reflection.MethodInfo miGncn =
typClsX.GetMethod("GetNewestCustomerName",new System.Type[0]);
This line of code creates a MethodInfo object miGncn
that holds the information for the unique public method GetNewestCustomerName() in the ClsX
object.
Invoke the Method
object oName = miGncn.Invoke(oClsX,null);
That's it, almost. The information we've been working towards is in the variable oName
after this line of code is executed. The second parameter null
is a placeholder for parameters (that we will use in the later articles) but our example requires no parameters, so we pass null
.
Curious that we call the MethodInfo object's Invoke
method and pass the actual instance object oClsX
as a parameter, but that's how it's done.
Cast the object returned
The Invoke
method always returns an object of type object
. We just need to cast it to a string to work with it.
string strNewestCust = (string) oName;
The Code
#using System.Reflection;
Assembly assem = Assembly.LoadFrom(@"c:\path\to\file.dll");
Type typClsX = assem.GetType("Fully.Qual.ClsX",true);
object oClsX = Activator.CreateInstance(typClsX);
MethodInfo miGncn = typClsX.GetMethod("GetNewestCustomerName",new System.Type[0]);
string strNewstCust = (string) miGncn.Invoke(oClsX,null);
Summary
In this article, we covered how to bind to and invoke a method at runtime through .NET Reflection. By loading the target assembly and instantiating a runtime class object, we were able to invoke a method on that class object and cast the returned object to a string.
- Part 1: Introduction to C# Reflection
- Part 2: string s = obj.Method()
- Part 3: string s = obj.Method(strString, iNumber)
- Part 4: Setting Object Properties
- Part 5: bool b = obj.Method(iNumber, ref string strString)
- Part 6: bool b = obj.Method(iNumber, out string strString)
- Part 7: Dealing with Remote Objects
Comments