Introduction
A couple of years ago, I got an interesting task. I had to develop a public Web Service which internally utilized 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
" with a single method Add
, taking two Integer
parameters and returning the sum of them:
Public Function Add(first As Integer, second As Integer) As Integer
Add = first + second
End Function
I 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 starts 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 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 a parameter list every time 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 now using the same method signatures as in the first example without the need to call 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 the .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.