Monday, June 12, 2006

Late Binding in C# and VB.NET


What is Late Binding?

Binding is the process of locating the declaration (that is, the implementation) that corresponds to a uniquely specified type. When this process occurs at run time rather than at compile time, it is called late binding.

Late binding in C# and VB.NET

Each .NET program assembly have Metadata which allows the user to dynamically load an assembly and execute methods of it, this is called Late Binding.

This Late Binding requires the use of Reflection in C# and VB.NET. In VB.NET it is optional because we have implicit late binding which allows us to have Late Binding without the use of Refelection.

Example

Now lets see, by example, how can we load and invoke assembly dynamically. We require two programs here.

MyAssembly.cs (This will contain simple class with few methods)
LoadInvoke.cs (This is the main assembly loader and invoke program which will load and invoke MyAssembly.dll (i.e. Compiled MyAssembly.cs file)


Listing 1: MyAssembly.cs

Listing 1: MyAssembly.cs


using System;

public class MyAssembly
{
public void PrintHello()
{
Console.WriteLine("Hello World");
}
}


Listing 2: LoadInvoke.cs



1 using System;
2 using System.Reflection;
3
4 public class LoadInvoke
5 {
6 public static void Main(string CmdArgs[])
7 {
8 Assembly a = Assembly.LoadFrom(CmdArgs[0]);
9
10 Types[] mytypes = a.GetTypes();
11
12 BindingFlags flags = (BindingFlags.NonPublic
13 BindingFlags.Public
14 BindingFlags.Static
15 BindingFlags.Instance)
16
17
18 foreach(Type t in mytypes)
19 {
20 MethodInfo[] mi = t.GetMethods(flags);
21
22 Object obj = Activator.CreateInstance(t);
23
24 foreach(m in mi)
25 {
26 m.Invoke(obj, null);
27 }
28 }
29 }
30 }



Compile Listing 1 program (MyAssembly.cs) at command prompt:

Csc /t:library MyAssembly.cs

This makes MyAssembly.dll file.

Then you compile Listing 2 program (LoadInvoke.cs) at your command prompt:

Csc LoadInvoke.cs

This makes LoadInvoke.exe

Run LoadInvoke.exe with command line argument as MyAssembly.dll
e.g. C:\>LoadInvoke Myassembly.dll

LoadInvoke loads MyAssembly.dll and executes (invoke) PrintHello method. The console window output is shown below

Hello World

Lets understand LoadInvoke program step by step

At line number 8 we have created an instance of Assembly object as a where MyAssembly.dll is loaded by Assembly.LoadFrom method, the assembly name to be loaded we got from the command line arguments. This method accepts one string argument and that is the name and path of assembly (i.e. MyAssembly.dll). So the object a is pointing to the loaded assembly MyAssembly.dll.

Assembly can have one or more classes in it (in our case it is MyAssembly public class), which we are obtaining from Assembly object’s instance method GetTypes(). This method returns array of Type object, which is saved in mytypes array.

Line number 12 – 16 gives the BindingFlags enumerations. Here is the explnation of each enumeration we used.

BindingFlags.NonPublic -> Specifies that non-public members are to be included in the search.
BindingFlags.Public -> Specifies that public members are to be included in the search.
BindingFlags.Static -> Specifies that static members are to be included in the search.
BindingFlags.Instance -> Specifies that instance members are to be included in the search.

Line number 18-28 shows the foreach loop browsing through each type in mytypes. Each type (i.e. class) can have one or more

methods in it. At line 20 we are executing t.GetMethods(flags) which returns the method information array and saved in array mi of type System.Reflection.MethodInfo

At Line 22 the instance of type t (i.e. MyAssembly class) is created using Activator.CreateInstance method. Here the instance is referenced with obj.

Now, as we have instance of class MyAssembly and the Method to execute also, so it is very easy to execute the instance method PrintHello. Here is the reference information:

obj -> refers to instance of MyAssembly class

mi -> MethodInfo array, contains all methods info from type t

m -> MethodInfo of method MyMethod1 available in class MyAssembly


Now, to execute the method PrintHello we need to use the Invoke method of MethodInfo m. See line number 26 m.Invoke(obj, null). It takes two parameters, first parameter should be type instance (instance variable obj) and second parameter is

object array of method parameters. In case your method contains parameters then you need to create object array of parameters. In our case MyMethod1 does not have any parameter, so we are passing null as a parameter here.


Calling COM Components from .NET using Refelection

In this example we are going to call a Excel application by loading COM component using .NET Late Binding



1 //Variable


2 Type excel;
3 object[] parameter= new object[1];
4 object excelObject;
5 try
6 {
7 //Get the excel object
8 excel = Type.GetTypeFromProgID("Excel.Application");
9 //Create instance of excel
10 excelObject = Activator.CreateInstance(excel);
11 //Set the parameter whic u want to set
12 parameter[0] = true;
13 //Set the Visible property
14 excel.InvokeMember("Visible", BindingFlags.SetProperty,

null, excelObject, parameter);
15 }
16 catch(Exception e)
17 {
18 Console.WriteLine("Error Stack {0} ", e.Message) ;
19 }
20 finally
21 {
22 //When this object is destroyed the Excel application

will be closed
23 //So Sleep for sometime and see the excel application
24 Thread.Sleep(5000);
25 //Relaese the object
26 //GC.RunFinalizers()
27 }


In line 8 we are using Type class method to get the COM object like the one which we have used is GetTypeFromProgID("Application") , this method get the COM ID from the System Registry.

In line 10 we are using the STATIC class member of Activator.CreateInstance() we create a new instance of the COM object.

In line 11 to invoke the methods,function and Properties of the COM object we have to use the InvokeMethod() of the Type object with proper settings , this methos takes many arguments of which the inportant one is the methods type ex property
(get or set)in example we have used a set property for Excel.Visible to make the Excel application visible.


Member Selection and Argument Coercion

The following example shows the three possible combinations of argument coercion (type conversion) and member selection.



public class CustomBinderDriver


{
public static void Main (string[] arguments)
{
Type t = typeof (CustomBinderDriver);
CustomBinder binder = new CustomBinder();
BindingFlags flags;

flags = BindingFlags.InvokeMethodBindingFlags.Instance
BindingFlags.PublicBindingFlags.Static;

// Case 1. Neither argument coercion nor member

selection is needed.
args = new Object[] {};
t.InvokeMember ("PrintBob", flags, binder, null, args);

// Case 2. Only member selection is needed.
args = new Object[] {42};
t.InvokeMember ("PrintValue", flags, binder, null, args);

// Case 3. Only argument coercion is needed.
args = new Object[] {"5.5"};
t.InvokeMember ("PrintNumber", flags, binder, null, args);
}

public static void PrintBob ()
{
Console.WriteLine ("PrintBob");
}

public static void PrintValue (long value)
{
Console.WriteLine ("PrintValue ({0})", value);
}

public static void PrintValue (String value)
{
Console.WriteLine ("PrintValue\"{0}\")", value);
}

public static void PrintNumber (double value)
{
Console.WriteLine ("PrintNumber ({0})", value);
}
}



In Case 1, no argument coercion or member selection is needed, because this is a direct call to non-overloaded function.
In Case 2, only member selection is needed, because the function we are calling is overloaded PrintValue(long) and PrintValue(string).
In Case 3, only argument coercion is needed, because the argument the function PrintNumber takes is double and the argument we are passing is string.


When to use?

1) In some applications, we don't know which assembly to load during compile time, so we ask the user to enter the assembly name and type during run time and the application can load assembly.

2) Using this, you can load an assembly at run time, obtain information about types in that assembly, specify the type that you want, and then invoke methods or access fields or properties on that type.

3) This technique is useful if you do not know an object's type at compile time, such as when the object type is dependent on user input.

4) Using this, we can also call the COM components.

Implicit Late binding

Visual Basic .NET allows you to use implicit late binding in your code; the Visual Basic
compiler calls a helper method that uses reflection to obtain the object type. The
arguments passed to the helper method cause the appropriate method to be invoked
at run time. These arguments are the instance (an object) on which to invoke the method,
the name of the invoked method (a string), and the arguments passed to the invoked
method (an array of objects).


An object is late bound when it is assigned to a variable declared to be of type Object. Objects of this type can hold references to any object. For example, the following code fragment declares an object variable to hold an object returned by the CreateObject function:


1'To use this example, you need Microsoft Excel
2 Option Strict Off 
' Option Strict Off allows late binding.
3 Sub TestLateBinding()
4 Dim xlApp As Object
5 Dim xlBook As Object
6 Dim xlSheet As Object
7 xlApp = CreateObject("Excel.Application")
8 'Late bind an instance of an Excel workbook.
9 xlBook = xlApp.Workbooks.Add
10 'Late bind an instance of an Excel worksheet.
11 xlSheet = xlBook.Worksheets(1)
12 xlSheet.Activate()
13 xlSheet.Application.Visible = True

' Show the application.
14 ' Place some text in the second row of the sheet.
15 xlSheet.Cells(2, 2) = "This is column B row 2"
16 End Sub



In the lines 4-6, we create an generiv Object.
In the lines 7-15, we call the methods to activate the Excel application and it is done
through Implicit Late binding because only at runtime the exact type of object is known.

Disadvantages of Using Late binding

1) Early Binding allow the compiler to make important optimizations that yield more
efficient applications.
2) Early-bound objects are significantly faster than late-bound objects.
3) It makes your code easier to read and maintain by stating exactly what kind of
objects are being used.
4) It enables useful features such as automatic code completion and Dynamic Help
because the Visual Studio .NET integrated development environment (IDE) can
determine exactly what type of object you are working with as you edit the code.
5) Early binding reduces the number and severity of run-time errors because it

0 Comments:

Post a Comment

<< Home