COM 互操作 (CCW) 中的重载 - IDispatch 名称包括后缀(_2、_3 等)

Posted

技术标签:

【中文标题】COM 互操作 (CCW) 中的重载 - IDispatch 名称包括后缀(_2、_3 等)【英文标题】:Overloads in COM interop (CCW) - IDispatch names include suffix (_2, _3, etc) 【发布时间】:2010-11-19 15:34:42 【问题描述】:

我有一个包含几个类的托管程序集,这些类具有重载方法。我通过

将程序集公开给 COM/IDispatch 调用者
[ComVisible(true)]

..并且还在程序集本身上设置正确的 Guid。我没有为 COM 互操作定义显式接口。这一切都是动态完成的。我在托管 DLL 上运行 regasm.exe /codebase 并将其注册为 COM 互操作。

当我运行 OleView 时,我可以看到程序集中各个类的 ProgId。但是,浏览这些 ProgId 并展开 IDispatch 节点,这些类没有 TypeLib 信息。

即便如此,我可以从脚本调用接受零参数的方法或接受一个参数的方法。如果还有一个接受多个参数的重载,我不能按名称调用该方法。我一直得到的错误是

Microsoft VBScript runtime error: Wrong number of arguments or invalid property assignment:  <methodname>

据此,我了解到 COM/IDispatch 客户端无法正确解析通过 COM 互操作公开的对象上的重载方法。


然后我添加了

[ClassInterface(ClassInterfaceType.AutoDual)]

...对每个有问题的课程。在 DLL 上的regasm.exe 之后,我可以在 IDispatch 节点下看到每个方法的类型库信息。

我发现重载的方法会自动获得一个包含附加后缀的名称。 MethodX 将在自动生成的 typelib 程序集中公开重载为 MethodX、MethodX_2、MethodX_3 等。

我发现通过引用带有这些后缀的方法名称,我可以调用重载方法,尽管不能使用通用名称。

更有趣的是,如果我从类中删除[ClassInterface(ClassInterfaceType.AutoDual)],我可以仍然以这种方式调用重载方法,从而避免Wrong number of arguments or invalid property assignment 错误。

我的问题是:这种行为 - 将数字后缀附加到成员名称 - 稳定吗?记录在案?可信?

【问题讨论】:

【参考方案1】:

COM 不支持方法重载,因此 .NET COM 互操作层必须即兴发挥。我不确定您所描述的名称修改是否在任何地方都有记录,但即使是这样,我也不认为使用它是一个好主意 - 对于 COM 用户来说,它仍然是相当不方便的 API。如果你想向 COM 公开你的类,最好的方法是编写一个独特的 COM 友好的[ComVisible] 接口,并隐藏类本身。以 COM 友好的方式处理重载的正确方法是使用带有一些 [Optional] 参数的单一方法(并委托给相应的 .NET 重载)。

【讨论】:

【参考方案2】:

根据我的经验,让 interop 生成 MethodMethod_1Method_2 等是正常且稳定的,但并不是很理想。令人讨厌的是,重载不会跨越托管/非托管边界。我尝试将 COM-Visible 方法重构为具有唯一名称的单独方法,以便 COM 使用者更清楚所调用的内容,而不是让它任意添加数字后缀。

【讨论】:

【参考方案3】:

是的,它在 MSDN 上有记录:

Advanced COM Interoperability: Exported Member Conversion

由于更改它将是文档功能的“重大更改”,我想您可以相信它是“稳定的”。最大的缺点是您的方法名称取决于它们在源文件中定义的顺序

但请注意,COM 支持 可选 参数,因此使用它们可能是重载的可行替代方案。如果您需要添加重载以与库的旧 .NET 客户端二进制兼容,我发现以下模式很有用:

// used for binary-compatibility with .NET clients who currently use 
// the old, one-parameter version
[ComVisible(false)]
void myMethod(String oneParameter)    
    ... 
   

// since this is the first COM-visible version, it is assigned the "correct" name.
void myMethod(String oneParameter, int newParameter = 0) 
    ...

由于 COM 支持可选参数,myMethod(string)myMethod(string, int) 都可以使用。

【讨论】:

注意:当使用 VB.NET 时,这种技术(两个重载只是可选参数不同)需要 VS 2012。

以上是关于COM 互操作 (CCW) 中的重载 - IDispatch 名称包括后缀(_2、_3 等)的主要内容,如果未能解决你的问题,请参考以下文章

如果它们不在 COM 互操作中执行,我应该将 LayoutKind.Auto 用于我的结构吗?

如何通过 COM 互操作在 .NET 对象上调用静态方法?

将反射与 COM 互操作一起使用

在 COM 互操作方法中将字符串作为参数传递

全局删除冲突重载

C# 4、COM 互操作和 UPnP:三驾马车