欺骗 .Net 为 COM 提供可选的 ref 参数可能带来的严重副作用

Possible nasty side effects of tricking .Net to have optional ref parameters for COM

最终编辑

我更彻底地测试了 "feature" 并写了一篇关于它的完整文章:Optional passed by reference parameters with C# for VBA COM APIs

欢迎任何反馈。


无论出于何种原因,在 C# 中,方法不能 可选 通过引用传递 (标有refout)参数。

但在其他基础架构中,例如 VBAVB6COM是可以的。

使用 COM 将 C# 与 VBA 桥接时,我找到了一种克服 C# 限制的方法,方法是将 ref 参数标记为 [Optional] 这是 AFAIK C# 编译器在其管道结束时生成的内容。

void SomeDotNetCSMethod([Optional] ref someParameter)

这似乎很有魅力:从 VBA 调用 C# 时,我可以省略 ref 参数,当然我可以从 .Net/C 中读取和更改它们# 边。

但是由于我还没有找到任何关于它的文章,所以我想确定这个 "trick" 没有不良副作用。

你知道吗?你能想象吗?


编辑

使用 [DefaultParameterValue] 属性,我可能找到了一种方法让 VBA 查看参数的默认值,但仅限于某些类型。

我会做更多测试以确认它是否按预期工作...

不,这不是指定可选参数的通用方法。您正在利用 C# v4 中添加的一个非常古怪的功能,它使 Office 互操作编程更容易接受。您通常可以期望它具有预期效果越接近互操作层类似于 VBA 或 IDispatch(又名 COM 自动化)。它不是通用的 COM 机制,更通用的方式是让客户端编译器观察类型库中的 [defaultvalue] 属性,并在方法调用中应用该值。很像 C# 做的。

参数的类型很重要,您忘记在代码段中指定它。但是期望它是 object。它匹配 COM 服务器中的 VARIANT,这是 Visual Basic 中非常常见的类型。还解释了 ref,旧 VB 版本中传递的默认参数是 ByRef。

在 C# v4 之前,编写 C# 代码来调用这样的服务器是一件非常乏味的事情,尤其是 Office 互操作代码中充斥着大量 ref Type.Missing。否则受支持脚本语言的需要的启发,这种环境不可能从类型库中确定可选参数的默认值。因此需要约定将 "caller did not specify the argument" 信号传递给被调用者,他们选择了类型 vtError 的变体,其值设置为 DISP_E_PARAMNOTFOUND。与 IDispatch::Invoke() 兼容。

请注意,这与 C# 和任何其他语言中处理可选参数的方式有何不同。总是由调用者解析可选参数的默认值,被调用者完全不知道代码省略了参数。对于 C#,该默认值在元数据中编码为 .param 值。编译器在必要时使用默认值来编译方法调用。

如果参数类型不是 object 那么您将调用一个不同的怪癖,现在调用者设置默认值。对于对象或接口,它将是 null。当然,这取决于您调用的代码如何将变体值解释为 'optional'。请注意 vtNullvtEmpty 可以具有相同的语义。