A couple of years ago I got an interesting task. I had to develop a public web service which utilized internally a third-party COM object. Sounds easy, the concept of COM Interop exists in .NET since the first release, so I didn't expect any difficulties on my way.
Just to be more specific let's say we have a very simple VB6 COM object "MyProject.MyClass" having a single method Add, taking two Integer parameters and returning a sum of them:
Public Function Add(first As Integer, second As Integer) As Integer
Add = first + second
End Function
I've started a new Visual Studio project, added a reference to the COM object and wrote the following code:
using System;
namespace ComTest
{
class Program
{
static void Main(string[] args)
{
MyProject.MyClass comObject = new MyProject.MyClass();
short sum = comObject.Add(1,2);
Console.Out.WriteLine("Early binding. Sum = " + sum);
Console.ReadLine();
}
}
}
It worked. But after some time I realized that the third-party COM object is updated on nearly a monthly basis. And the COM object has been probably developed in VB6 with no version compatibility settings, resulting in constantly changing GUIDs even when the interface signatures haven't changed. As a result my program started to crash showing the following message:
An unhandled exception of type 'System.InvalidCastException' occurred in ComTest.exe
I had two options: either recompile my web service each time I receive a new COM object or to use late binding. Obviously I went for the last option.
My C# code looked like this:
using System;
using System.Reflection;
namespace ComTest
{
class Program
{
static void Main(string[] args)
{
System.Type objType = System.Type.GetTypeFromProgID("MyProject.MyClass");
object comObject = System.Activator.CreateInstance(objType);
object[] oParms = new Object[] { 1, 2 };
short sum = (short)objType.InvokeMember("Add", BindingFlags.InvokeMethod, null, comObject, oParms);
Console.Out.WriteLine(sum);
Console.ReadLine();
}
}
}
It worked, but imagine if you have not just one method in COM object but many of them. Building every time a parameter list and calling InvokeMember is not the most pleasant way to spend your time in the office. And there was no other option until Visual C# 2010. Thanks to the new dynamic type, it is possible now to declare an object of a type that bypasses static type checking. At compile time, an element that is typed as dynamic is assumed to support any operation. Therefore, we can write the following code now:
using System;
using System.Reflection;
namespace ComTest
{
class Program
{
static void Main(string[] args)
{
System.Type objType = System.Type.GetTypeFromProgID("MyProject.MyClass");
dynamic comObject = System.Activator.CreateInstance(objType);
short sum = comObject.add(1, 2);
Console.Out.WriteLine("Late binding with dynamic type. Sum = " + sum);
Console.ReadLine();
}
}
}
So we are using now the same method signatures as in first example without a need to use a call to InvokeMember. However, if the method signature is not valid, errors are caught at run time. How will it help me? Very simple. First I start developing my application by adding a reference to the COM object. It's so easy to use .NET wrappers, generated for you by Visual Studio. When I am almost ready to deploy, I remove the reference and use GetTypeFromProgID instead.
That's it.