65.9K
CodeProject 正在变化。 阅读更多。
Home

新的 C# dynamic 类型如何简化对晚期绑定 COM 对象的访问

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (9投票s)

2011 年 1 月 21 日

CPOL

2分钟阅读

viewsIcon

58201

解释了新的动态类型如何简化对后期绑定 COM 对象的访问。

引言

几年前,我收到了一项有趣的开发任务。我需要开发一个公共 Web 服务,该服务内部使用第三方的 COM 对象。听起来很简单,.NET 自第一版发布以来就存在 COM Interop 的概念,所以我预计在开发过程中不会遇到任何困难。

为了更具体地说明,假设我们有一个非常简单的 VB6 COM 对象“MyProject.MyClass”,它有一个名为 Add 的方法,接受两个 Integer 参数并返回它们的和。

Public Function Add(first As Integer, second As Integer) As Integer

  Add = first + second

End Function

我启动了一个新的 Visual Studio 项目,添加了对 COM 对象的引用,并编写了以下代码

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();
      }
  }
}

它运行正常。但一段时间后,我意识到第三方 COM 对象几乎每月都会更新。而且该 COM 对象可能是用 VB6 开发的,没有版本兼容性设置,导致即使接口签名没有更改,GUID 也会不断变化。结果,我的程序开始崩溃,并显示以下消息

An unhandled exception of type 'System.InvalidCastException' occurred in ComTest.exe

我有两个选择:每次收到新的 COM 对象时都重新编译我的 Web 服务,或者使用后期绑定。显然,我选择了后者。我的 C# 代码如下所示

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();
      }
  }
}

它运行正常,但想象一下,如果 COM 对象中不仅仅有一个方法,而是有很多方法。每次构建参数列表并调用 InvokeMember 并不是在办公室里度过美好时光的最佳方式。在 Visual C# 2010 之前,没有其他选择。感谢新的 dynamic 类型,现在可以声明一种绕过静态类型检查的类型。在编译时,被键入为 dynamic 的元素被假定支持任何操作。因此,我们现在可以编写以下代码

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();
      }
  }
}

因此,我们现在使用了与第一个示例中相同的函数签名,而无需调用 InvokeMember。但是,如果方法签名无效,则会在运行时捕获错误。这对我有什么帮助?很简单。首先,我通过添加对 COM 对象的引用来开始开发我的应用程序。使用 Visual Studio 为您生成的 .NET 包装器非常容易。当我几乎准备好部署时,我删除引用并使用 GetTypeFromProgID 代替。

就是这样。

© . All rights reserved.