In simplest words, late binding is a technique, in which you can create an instance of a given type, and can invoke its methods, at runtime, without having knowledge of its existence at compile time.
System.Activator
class plays a pivotal role in late binding process.
Let us understand it by creating:
- A simple Class library “
MyMathLib
” which exposes few methods, let's say Add
, Subtract
, Multiply
. - Console bases client program, that will use this library using the conventional (early binding) method.
- Console bases client program, that will use this library using the late binding method.
Creating the Class Library
Create a Class library, let’s name it “MyMathLib
” choosing the “Class Library” template from the project wizard. Default project is created with a public class Class1
defined in Class1.cs.
Little house keeping.
Rename the Class1
as “MathClass
” using the refactor menu.
Rename the class1.cs as MathClass.cs.
Now define methods Add
, Subtract
and Multiply
for MathClass
as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMathLib
{
public class MathClass
{
public double Add(double dblX, double dblY)
{
return (dblX + dblY);
}
public double Subtract(double dblX, double dblY)
{
return (dblX – dblY);
}
public double Multiply(double dblX, double dblY)
{
return (dblX * dblY);
}
}
}
Compile and build library.
Creating the Application That Will Use This Library
Create a Console application, let’s name it “TestEarlyBinding
” choosing the “Console Application” template from the project wizard. Default project is created.
Little house keeping.
Add Reference of MathLib class library project, created earlier.
Write code in the main function to use this library as shown below:
using System;
using System.Text;
using MyMathLib;
namespace TestEarlyBinding
{
class Program
{
static void Main(string[] args)
{
double dblResult = 0;
double dblX = 200; double dblY = 200;
Console.WriteLine("Testing early binding");
MathClass mathObj = new MyMathLib.MathClass ();
dblResult = mathObj.Add(dblX, dblY);
Console.WriteLine("Adding {0} and {1} results to {2}", dblX, dblY, dblResult);
dblResult = mathObj.Subtract (dblX, dblY);
Console.WriteLine("Adding {0} and {1} results to {2}", dblX, dblY, dblResult);
dblResult = mathObj.Multiply(dblX, dblY);
Console.WriteLine("Adding {0} and {1} results to {2}", dblX, dblY, dblResult);
}
}
}
Compile and build and here is the output.
Till now, it was the default way, we used to do things, but this post is about late binding.
So using the same class library with late binding, let’s create one more console based project. Let’s call it TestLateBinding
.
using System;
using System.Text;
using System.Reflection;
namespace TestLateBidning
{
class Program
{
static void Main(string[] args)
{
double dblResult = 0;
double dblX = 200; double dblY = 100;
Console.WriteLine("Testing late binding");
Assembly assem = null;
Console.WriteLine("Loading MyMathLib assembly . . .");
try
{
assem = Assembly.Load("MyMathLib");
}
catch (Exception eX)
{
Console.WriteLine("Error while loading MyMathLib Error
[{0}] \n\nMyMathLib.dll not found in application Folder", eX.Message);
return;
}
Console.WriteLine("Creating Instance of MathClass object . . .");
Type mathType = assem.GetType("MyMathLib.MathClass");
object mathObjLB = Activator.CreateInstance(mathType);
Console.WriteLine("Invoke method [Add] . . .");
MethodInfo miAdd = mathType.GetMethod("Add");
dblResult = (double)miAdd.Invoke(mathObjLB, new object[] { 100, 200 });
Console.WriteLine("Adding {0} and {1} results to {2}", dblX, dblY, dblResult);
Console.WriteLine("Invoke method [Subtract] . . .");
MethodInfo miSub = mathType.GetMethod("Subtract");
dblResult = (double)miSub.Invoke(mathObjLB, new object[] { 100, 200 });
Console.WriteLine("Subtracting {0} and {1} results to {2}", dblX, dblY, dblResult);
Console.WriteLine("Invoke method [Multiply] . . .");
MethodInfo miMul = mathType.GetMethod("Multiply");
dblResult = (double)miMul.Invoke(mathObjLB, new object[] { 100, 200 });
Console.WriteLine("Multiply {0} and {1} results to {2}", dblX, dblY, dblResult);
}
}
}
Explanation
Assembly assem = null;
Console.WriteLine("Loading MyMathLib assembly . . .");
try
{
assem = Assembly.Load("MyMathLib");
}
catch (Exception eX)
{
. . . . .
return
}
Assembly
class represents an assembly, which is a valid building block of a common language runtime.
Load
method simply loads an assembly, whose name has been provided.
Type mathType = assem.GetType("MyMathLib.MathClass");
object mathObjLB = Activator.CreateInstance(mathType);
Activator
class contains methods to create types of object of the specified type, locally or remotely.
MethodInfo miAdd = mathType.GetMethod("Add");
GetMethod
is member function of Type
class, that searches the given method name, and returns the MethodInfo
, MethodInfo
class discovers the attributes of a method access its metadata.
dblResult = (double)miAdd.Invoke(mathObjLB, new object[] { 100, 200 });
(mathObjLB, new object[] { 100, 200 });
Invoke
method of MethodInfo
class simply calls the method, using the required parameters.
Similarly other methods (Subtract
, Multiply
) are discovered and invoked.
Build and execute.
Oops, there was an error, as it could not find the MyMathLib.dll in the test application executable (TestLateBinding.exe) folder.
Just copy the MyMathLib.dll to the test application’s executable folder and execute the client again and you will see what was expected.
Hope it was useful!
More than 10 years of experience in designing and development of GUIs and Middleware for industrial control systems.