理解COM c#接口

6

Microsoft.Office.Interop.Word._Document接口有一个带有以下签名的方法:

void Close(ref object SaveChanges = Type.Missing, ref object OriginalFormat = Type.Missing, ref object RouteDocument = Type.Missing);

我有几个不太理解的问题:
  1. ref参数不能有默认值。
  2. 默认值必须是一个常量,而Type.Missing不是。
  3. 在调用此方法时,我可以使用Close(false)——通常情况下,ref参数需要一个可分配的变量?
  4. 当导航到Visual Studio中Type的定义时,它会带我到_Document.Type属性,但这个属性没有名为Missing的属性。这是VS中的一个错误吗?
谢谢您的任何解释。

  1. 和2.:很简单,Interop库不是用C#编写的:) 3.:你需要一个变量。 4.:它应该带你到System.Type.Missing
总的来说,如果你要使用这样的COM库,请使用VB.NET - 这将为您节省大量麻烦。毕竟,VB是COM语言之一。
- Luaan
@Luaan 我认为Interop必须是合法的C# - 这是否意味着从c# dll中在VS中查看元数据时,它不一定是有效的C#?3.:你需要一个变量。 - 我刚刚创建了一个将false作为字面值传递的项目,它百分之百地工作。 - wezten
2
这是元数据。它必须是有效的IL,但不一定是有效的C# - VS为您翻译元数据只是一种方便,这并不意味着它最初是用C#编写的。如果必须这样做,那么在CLR上拥有更多语言的意义何在?第3条:哎呀,我以前成功使用过那个。只是我看到了太多的SO问答,总是已经使用了“ref”,抱歉 :)) - Luaan
如果你在回答中加入“它必须是有效的IL,但不是有效的C#”这句话,我会接受它,因为我认为这就是问题的答案。 - wezten
2个回答

4
事实上,InterOp库并不是用C#编写的,也不必遵守C#的规则。它唯一需要的是有效的IL代码。
Visual Studio元数据查看器会尽其所能地以您选择的语言(在本例中为C#)显示元数据,因为这通常比使用IL代码更易读。
这在某些情况下可能会引人误解(例如,ref参数实际上不必是C#中的ref,C#没有默认参数之前的默认参数、默认参数中的非常量值…),但这实际上只是一个副作用,因为VS并不真正知道用于构建库的语言,而即使它知道,您也不希望看到它-您关心的是在C#中公开给您的接口,或者尽可能接近它。
请注意,这些默认参数与C#中的完全不同-C#中的默认参数在客户端编译时解析(例如,在引用的库中更改默认参数不会在用户代码中更改它们,直到您重新编译该代码),而这些则不同。正如我所说,VS尽力近似,但CLR语言确实可以非常不同。

看了@HansPassant的回答后,我有一些评论。似乎这一切都是按设计来的,而不是VS元数据查看器尽力而为。此外,我认为最后一段是不正确的,COM默认参数也被嵌入到客户端中。 - wezten

3

这是C# 4版本引入的一个怪异现象。它不仅限于COM互操作代码,您自己的代码也可能会出现这种情况。可以尝试以下操作:

using System;
using System.Runtime.InteropServices;

class Program {
    static void Example([Optional] object arg) { }
    static void Main(string[] args) {
        Example(   // <== Look at the IntelliSense popup here
    }
}

这种行为是由[Optional]属性触发的。在C#中,它已经存在了很长时间,但以前并不特别有用。与其他语言(如VB.NET和C++/CLI)不同。从C# v4开始,它会以不同的方式解释该属性,并且编译器将硬编码Type.Missing作为object类型参数的可选值。尝试将参数类型更改为string,注意默认值变得不同。就像你预期的那样,是null。
当然,这并不是很美观。在普通的C#代码中,Type.Missing是一个相当奇怪的object默认值。每个人都希望是null。然而,这非常实用,在版本4之前使用C#编写Office互操作代码是一项相当可怕的任务。顺便说一下,如果公司这样做,可能会遇到麻烦,如果Neelie Kroes得知此事,她会让微软支付10亿欧元的罚款:)

我将此标记为答案,因为它回答了第1和第2点。至于第3点,《C#核心技术指南》这本书解释说,这是针对COM的特殊允许,以简化调用COM的代码。第4点肯定是一个错误 - 它是绝对不正确的。 - wezten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接