7.3 Dynamic Type Loading

only for RuBoard

The process of locating a type declaration and verifying that its methods are used correctly is called binding . Binding that occurs at compile time is called early binding . When it happens at runtime, it is known as late binding .

Visual Basic .NET uses reflection to implement late binding. Consider the following code:

 Dim fourOneOne As Object fourOneOne = New ServerInfo( ) fourOneOne.DoTask(Allocate2GigForTheBrowser) 

Here, fourOneOne is declared as an Object but instantiated as ServerInfo (from Example 7-1). The DoTask method call is a late-bound call. In situations like this, the method is called at runtime through the Type.InvokeMember method. Try to avoid writing code like this, if possible. You will incur a performance penalty for late binding.

In more exotic architectures, especially distributed systems, late binding is a must. Think about a system centered around SOAP, for instance. A SOAP envelope that describes an object and a method call is sent to a server located halfway around the world. The remote server spawns an instance of the object, calls the appropriate method, and sends the results back to the caller. This is late binding at the extreme!

7.3.1 Using Dynamically Loaded Types

Reflection not only allows you to inspect the types contained within an assembly, it makes it possible for you to create instances of those types at runtime. You can then call methods on those objects and use them just like any other objects.

Loading a type at runtime and calling its methods is easy, but more details need to be discussed, so let's piece together the example one fragment at a time. Start with loading the assembly. As in Example 7-2, the assembly containing the type must first be loaded into an application domain. Then a call to Assembly.GetType can be used to get a reference (not an instance) to the needed type:

 Imports System Imports System.Reflection     'This examples assumes ServerInfo.dll is in the current directory Dim a As [Assembly] = [Assembly].LoadFrom("ServerInfo.dll") Dim siType As Type = a.GetType("ServerInfo") 

You have already seen how the info classes can provide information about the specifics of a class. The exciting thing is that the same classes can be used to make runtime calls on an object. The starting point is to retrieve a MethodInfo or PropertyInfo object representing the method or the property to be called. To get a reference to a method, call Type.GetMethod ; to get a reference to a property, call Type.GetProperty . Instead of calling the GetProperty method, you can also call Type.GetMethod to access the MethodInfo object representing either a property's get accessor or its set accessor. For example, the following code retrieves the MethodInfo object representing the DoTask method and also retrieves a MethodInfo object representing the MachineTime property's get accessor:

 'Get DoTask method Dim doTask As MethodInfo doTask = siType.GetMethod("DoTask")          'This was done as a function instead of a property in order 'to demonstrate shared methods Dim machineTime As MethodInfo machineTime = siType.GetMethod("GetMachineTime") 
7.3.1.1 System.Activator

So far, although the code retrieved a Type object representing the ServerInfo class, an instance of ServerInfo doesn't actually exist. To create it, use the System.Activator class. This class contains all methods necessary to create objects locally or remotely, or to obtain references to existing objects.

To create an object of a given type, call Activator.CreateInstance , which simply takes the type to be created:

 Dim si As Object si = Activator.CreateInstance(siType) 

If ServerInfo 's constructor had arguments, each would have to be packed into an object array and passed along with the type:

 Dim d As Double = 10 Dim s As String = "Test" Dim args( ) As Object = {d, s} Dim si As Object = Activator.CreateInstance(siType, args) 
7.3.1.2 Dynamic event handling

Before invoking methods at runtime, it's probably a good idea to wire up the handler to deal with the event that is raised when ServerInfo.DoTask is invoked. Doing this dynamically is not difficult, but it does have to be done precisely in order to work. The first step is to create a method that matches the event's signature:

 'The event handler for ServerInfo.TaskCompleted Public Sub OnTaskCompleted(ByVal obj As Object, ByVal e As EventArgs)     Console.WriteLine("The task has been completed") End Sub 

After having seen ConstructorInfo , MethodInfo , and PropertyInfo , what class could you use to obtain event information? It's called EventInfo , and to get it, call Type.GetEvent and ask for the event by name . Then finishing the job only requires calling EventInfo.AddEventHandler . This method takes the event source as the first parameter (the ServerInfo object) and a delegate of type EventHandler as the second:

 'Dynamically hook up to event source Dim evtInfo As EventInfo = siType.GetEvent("TaskCompleted") Dim evtHandler As EventHandler = AddressOf OnTaskCompleted evtInfo.AddEventHandler(si, evtHandler) 
7.3.1.3 Calling methods and properties dynamically

MethodInfo.Invoke calls methods at runtime. It takes two parameters: an object instance on which to call the method and an object array containing the parameters to the method.

ServerInfo.DoTask has one parameter: the task that is to be performed. The tricky part of making this call, however, is the fact that the parameter that must be passed is a member of the Tasks enumeration, which is also declared in the ServerInfo.dll assembly.

You must call Assembly.GetType to return a Type representing the Tasks enumeration. Then GetMember is called from the returned type. GetMember brings back the individual member of the enumerationin this case, WasteMemory . Now the parameter array can be packaged. When the "task" is passed to Activator.CreateInstance , the declaring type is used:

 'Package DoTask parameters and call Dim taskType As Type = a.GetType("ServerInfo+Tasks") Dim taskInfo( ) As MemberInfo = taskType.GetMember("WasteMemory") Dim taskParam As Object = Activator.CreateInstance(taskInfo(0).DeclaringType) Dim taskParams( ) As Object = {taskParam} doTask.Invoke(si, taskParams) 

This code should cause the OnTaskCompleted event to be called indirectly through the event handler that is assigned dynamically.

GetMachineName is a different story. It's a shared method, so an object instance is not required to call it. Furthermore, it takes no parameters, so Nothing can be passed for both arguments of the Invoke method:

 'Call GetMachineTime Dim result As Object = machineTime.Invoke(Nothing, Nothing) Dim dt As DateTime = Convert.ToDateTime(result) Console.WriteLine(dt.ToString( )) 

Properties are handled differently. To get and set the value of a property, call PropertyInfo.GetValue and PropertyInfo.SetValue . The property can be referred to by name:

 'Get machine name Dim pi As PropertyInfo = siType.GetProperty("MachineName") Console.WriteLine(pi.GetValue(si, Nothing)) 

Example 7-4 contains a complete listing of everything up to this point. Compile and try it. The output should look like this:

 The task has been completed 4/18/2002 9:41:22 PM LOGAN-5 192.168.1.101 288 MB Free Processor: 1.5625% used 
Example 7-4. Dynamic type loading and method invocation
 'latebind.vb 'References ServerInfo.dll 'Assumes ServerInfo.dll is in same directory as executable     Imports System Imports System.Net Imports System.Reflection Imports ServerInfo.ServerInfo     Public Class LateBind         'Event Handler     Public Sub OnTaskCompleted(ByVal obj As Object, ByVal e As EventArgs)         Console.WriteLine("The task has been completed")     End Sub         Public Sub New( )         Dim a As [Assembly]         a = [Assembly].LoadFrom("ServerInfo.dll")         Dim siType As Type = a.GetType("ServerInfo.ServerInfo")             '  Get DoTask method  Dim doTask As MethodInfo         doTask = siType.GetMethod("DoTask")             '  GetAvailableMemory  Dim getMem As MethodInfo         getMem = siType.GetMethod("GetAvailableMemory")             '  GetProcessorUsed  Dim getProc As MethodInfo         getProc = siType.GetMethod("GetProcessorUsed")             '  This was done as a function instead of a property in order  '  to demonstrate shared methods  Dim machineTime As MethodInfo         machineTime = siType.GetMethod("GetMachineTime")             '  Create instance of object  Dim si As Object         si = Activator.CreateInstance(siType)             '  Dynamically hook up to event source  Dim evtInfo As EventInfo = siType.GetEvent("TaskCompleted")         Dim evtHandler As EventHandler = AddressOf OnTaskCompleted         evtInfo.AddEventHandler(si, evtHandler)             '  Package DoTask parameters and call  Dim taskParams( ) As Object = {Tasks.WasteMemory}         doTask.Invoke(si, taskParams)             '  Output results  Dim result As Object = machineTime.Invoke(Nothing, Nothing)         Dim dt As DateTime = Convert.ToDateTime(result)         Console.WriteLine(dt.ToString( ))             '  Get machine name  Dim pi As PropertyInfo = siType.GetProperty("MachineName")         Console.WriteLine(pi.GetValue(si, Nothing))             '  Get IP  pi = siType.GetProperty("IPAddress")         result = pi.GetValue(si, Nothing)         Dim ip As IPAddress = CType(result, IPAddress)         Console.WriteLine(ip.ToString( ))             '  Get free memory  result = getMem.Invoke(si, Nothing)         Dim mbytesFree As Integer = Convert.ToInt32(result)         Console.WriteLine(String.Format("{0} MB Free", mbytesFree))             '  Get processor  result = getProc.Invoke(si, Nothing)         Dim used As Single = Convert.ToSingle(result)         Console.WriteLine(String.Format("Processor: {0}% used", used))         End Sub     End Class     Public Class Application         Public Shared Sub Main( )         Dim test As New LateBind( )         Console.ReadLine( )     End Sub     End Class 
only for RuBoard


Object-Oriented Programming with Visual Basic. Net
Object-Oriented Programming with Visual Basic .NET
ISBN: 0596001460
EAN: 2147483647
Year: 2001
Pages: 112
Authors: J.P. Hamilton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net