Late Binding

Once you have discovered a method, it's possible to invoke it using reflection. For example, you might like to invoke the Cos( ) method of System.Math, which returns the cosine of an angle.

TIP: You could, of course, call Cos( ) in the normal course of your code, but reflection allows you to bind to that method at runtime. This is called late-binding and offers the flexibility of choosing at runtime which object you will bind to and invoking it programmatically. This can be useful when creating a custom script to be run by the user or when working with objects that might not be available at compile time. For example, by using late-binding, your program can interact with the spellchecker or other components of a running commercial word processing program such as Microsoft Word.

To invoke Cos( ), you will first get the Type information for the System.Math class:

Type theMathType = Type.GetType("System.Math");

With that type information, you can dynamically load an instance of that class by using a static method of the Activator class.

The Activator class contains four methods, all static, which you can use to create objects locally or remotely or to obtain references to existing objects. The four methods are: CreateComInstanceFrom, CreateInstanceFrom, GetObject, and CreateInstance:

CreateComInstanceFrom

Used to create instances of COM objects.

CreateInstanceFrom

Used to create a reference to an object from a particular assembly and type name.

GetObject

Used when marshaling objects. Marshaling is discussed in detail in Chapter 19.

CreateInstance

Used to create local or remote instances of an object. You'll use this method to instantiate an object of the System.Math class.Object theObj = Activator.CreateInstance(theMathType);

You now have two objects in hand: a Type object named TheMathType, which you created by calling GetType, and an instance of the System.Math class named theObj, which you instantiated by calling CreateInstance.

Before you can invoke a method on the object, you must get the method you need from the Type object, theMathType. To do so, you'll call GetMethod(), and you'll pass in the signature of the Cos method.

The signature, you will remember, is the name of the method (Cos) and its parameter types. In the case of Cos(), there is only one parameter: a double. Whereas, Type.GetMethod takes two parameters: the first represents the name of the method you want, and the second represents the parameters. The name is passed as a string; the parameters are passed as an array of types:

This code declares the array of Type objects and then fills the first element (paramTypes[0]) with a Type representing a double. You obtain that type representing a double by calling the static method Type.GetType(), passing in the string System.Double.

You now have an object of type MethodInfo on which you can invoke the method. To do so, you must pass in the actual value of the parameters, again in an array:

TIP: Note that you've created two arrays. The first, paramTypes, holds the type of the parameters. The second, parameters, holds the actual value. If the method had taken two arguments, you'd have declared these arrays to hold two values. If the method took no values, you still would create the array, but you would give it a size of zero!

That was a lot of work just to invoke a single method. The power, however, is that you can use reflection to discover an assembly on the user's machine, use reflection to query what methods are available, and then use reflection to invoke one of those members dynamically!

Reflection Emit

So far we've seen reflection used for three purposes: viewing metadata, type discovery, and dynamic invocation. You might use these techniques when building tools (such as a development environment) or when processing scripts. The most powerful use of reflection, however, is with reflection emit.

Reflection emit supports the dynamic creation of new types at runtime. You can define an assembly to run dynamically or to save itself to disk, and you can define modules and new types with methods that you can then invoke.

TIP: The use of dynamic invocation and reflection emit should be considered an advanced topic. Most developers will never have need to use reflection emit. This demonstration is based on an example provided at the Microsoft Author's Summit, Fall 2000.

To understand the power of reflection emit, you must first consider a slightly more complicated example of dynamic invocation.

Problems can have general solutions that are relatively slow and specific solutions that are fast. To keep things manageably simple, consider a DoSum( ) method, which provides the sum of a string of integers from 1...n, where n will be supplied by the user.

Thus, DoSum(3) is equal to 1+2+3, or 6. DoSum(10) is 55. Writing this in C# is very simple:

DoSum2 runs more quickly than DoSum1 does. How much more quickly? To find out, you'll need to put a timer on both methods. To do so, you'll use a DateTime object to mark the start time and a TimeSpan object to compute the elapsed time.

For this experiment, you need to create two DoSum( ) methods; the first will use the loop and the second will not. You will call each 1,000,000 times. (Computers are very fast, so to see a difference you have to work hard!) You'll then compare the times. Example 18-8 illustrates the entire test program.

As you can see, both methods returned the same answer (one million times!), but the brute-force method was six times faster.

Is there a way to avoid the loop and still provide a general solution? In traditional programming, the answer would be no, but with reflection you do have one other option. You can, at runtime, take the value the user wants (20, in this case) and write out to disk a class that implements the brute-force solution. You can then use dynamic invocation to invoke that method.

There are at least three ways to achieve this result, each increasingly elegant. The third, reflection emit, is the best, but a close look at two other techniques is instructive. If you are pressed for time, you might wish to jump ahead to the section entitled "Dynamic Invocation with Reflection Emit", later in this chapter.