C#.NET是否支持IDispatch后期绑定?


问题

我的问题是: C#nativly支持后期绑定IDispatch吗?


假装我正在尝试自动化Office,同时兼容客户安装的任何版本。

在.NET世界中,如果您使用Office 2000进行开发,那么从现在到结束,每个开发人员和每个客户都需要拥有Office 2000。

在.NET之前的世界中,我们使用COM与Office应用程序进行通信。

例如:

1)使用版本独立的ProgID

"Excel.Application" 

解析为:

 clsid = {00024500-0000-0000-C000-000000000046} 

然后使用COM,我们要求将其中一个类实例化为一个对象:

 IUnknown unk; CoCreateInstance( clsid, null, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IUnknown, out unk); 

现在我们即将参加比赛 – 能够在我的应用程序中使用Excel。 当然,如果你真的想要使用该对象,你必须调用一些方法来调用方法。

我们可以获得各种接口声明,并将其翻译成我们的语言。 这项技术很好,因为我们得到了

  • 早期绑定
  • 代码洞察
  • 编译类型语法检查

一些示例代码可能是:

 Application xl = (IExcelApplication)unk; ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid); Worksheet worksheet = workbook.ActiveSheet; 

但是使用接口有一个缺点:我们必须得到各种接口声明,转换成我们的语言。 我们坚持使用基于方法的调用,必须指定所有参数,例如:

 ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid); xl.Worksheets.Add(before, after, count, type, lcid); 

事实certificate,在现实世界中,我们愿意放弃这样的缺点:

  • 早期绑定
  • 代码洞察
  • 编译时语法检查

而是使用IDispatch后期绑定:

 Variant xl = (IDispatch)unk; Variant newWorksheet = xl.Worksheets.Add(); 

因为Excel自动化是为VB脚本设计的,所以即使没有它们也没有过载,也可以省略很多参数。

注意:不要混淆我的Excel示例以及我想使用IDispatch的原因。 并非每个COM对象都是Excel。 某些COM对象除了通过IDispatch之外没有任何支持。

相对而言,您可以在C#中使用后期绑定IDispatch绑定。

http://support.microsoft.com/kb/302902

这是使用Excel的一些示例。 这样你就不需要在微软臃肿的PIA上添加不必要的依赖:

 //Create XL Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); //Get the workbooks collection. // books = xl.Workbooks; Object books = xl.GetType().InvokeMember( "Workbooks", BindingFlags.GetProperty, null, xl, null); //Add a new workbook. // book = books.Add(); Objet book = books.GetType().InvokeMember( "Add", BindingFlags.InvokeMethod, null, books, null ); //Get the worksheets collection. // sheets = book.Worksheets; Object sheets = book.GetType().InvokeMember( "Worksheets", BindingFlags.GetProperty, null, book, null ); Object[] parameters; //Get the first worksheet. // sheet = sheets.Item[1] parameters = new Object[1]; parameters[0] = 1; Object sheet = sheets.GetType().InvokeMember( "Item", BindingFlags.GetProperty, null, sheets, parameters ); //Get a range object that contains cell A1. // range = sheet.Range["A1]; parameters = new Object[2]; parameters[0] = "A1"; parameters[1] = Missing.Value; Object range = sheet.GetType().InvokeMember( "Range", BindingFlags.GetProperty, null, sheet, parameters ); //Write "Hello, World!" in cell A1. // range.Value = "Hello, World!"; parameters = new Object[1]; parameters[0] = "Hello, World!"; objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, null, range, parameters ); //Return control of Excel to the user. // xl.Visible = true; // xl.UserControl = true; parameters = new Object[1]; parameters[0] = true; xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty, null, xl, Parameters ); xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty, null, xl, Parameters ); 

你必须等待C#4.0出来才能获得你想要的后期绑定。 每当我需要互操作能力时,我都会切换回VB.Net模式,这样我就可以利用C#似乎缺乏的COMfunction。

我使用的简单方法是在VB.Net中创建一个类,它执行IDispatch工作,然后公开我想用作包装器方法的方法,然后我可以从我的C#代码中随意调用它们。 不是最优雅的解决方案,但它让我在过去的几个月中脱离了一两个。

C#4的dynamic关键字支持IDispatch和后期绑定。 您可以阅读Sam Ng的动态系列以获取更多信息

哦,C#4今天只作为CTP提供。 您必须等待Visual Studio vNext或使用beta(在Windows Server 2008 Virtual PC上运行)才能使用它。

如果你花时间编写一个包含你想要的对象的方法和属性的接口并添加一些属性(我从内存写入,所以细节可能不是),你可能会在C#2.0 / 3.0中使用更好的代码。是的,但我发誓它对我有用…)

  using System.Runtime.Interopservices; [Guid("00024500-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] interface IExcel { // sample property string Name{get;} // more properties } // and somewhere else void main() { Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); IExcel excel = (IExcel)xl; string name = xl.name } 

如前所述,代码不会开箱即用,它更像是在msdn中挖掘的内容。

正如其他人所说 – 使用c#4的“动态”关键词。 这是一个简单的例子 – 它比使用“InvokeMethod”更加苛刻

 dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); dynamic books = xl.Workbooks; dynamic book = books.Add(); Console.WriteLine(books.Count); //Writes 1 foreach (dynamic b in books) { Console.WriteLine(b.Name); //Writes "Book1" } 

嘿Dude,我目前有两个codeplex项目来解决这个问题。

第一个是LateBindingApi.Excel http://excel.codeplex.com将后期绑定的调用映射映射到众所周知的对象模型。 这是以下项目的测试项目。

第二个是CodeGenerator http://latebindingapi.codeplex.com,该工具从COM Type库创建c#项目。 生成的项目包括具有后端访问COM服务器的映射器对象。 重点是该工具将不同版本的COM类型库转换为单个项目(例如excel 9,10,11),并使用自定义的SupportByLibrary Attribut标记所有实体。 我已经使用这个工具分析了版本9,10,11,12,14中的所有办公应用程序并生成了ac#解决方案,它在主页上带有示例代码的测试版。