C#4,为了简化COM互操作,允许调用者在COM接口中省略ref参数前面的ref关键字。
我很惊讶今天看到这也适用于扩展COM接口的扩展方法。请参阅以下内容,编译代码:
using System;
using System.Runtime.InteropServices;
[ComImport, Guid ("cb4ac859-0589-483e-934d-b27845d5fe74")]
interface IFoo {
}
static class Program {
public static void Bar (this IFoo self, ref Guid id)
{
id = Guid.NewGuid ();
}
static void Main ()
{
Foo (null);
}
static void Foo (IFoo o)
{
Guid g = Guid.NewGuid ();
Console.WriteLine (g);
// note that g is passed as is, and not as ref g
o.Bar (g);
Console.WriteLine (g);
}
}
我没有在规范中找到任何解释这种行为的内容。
我的感觉是COM接口之外的代码,即使它是扩展COM接口的扩展方法,也应该遵循常规的C#规则,并强制使用ref关键字。因此,我提交了bug on connect。并不是说我认为这将被修复,即使它被视为一个错误,那里已经有代码依赖于此。
错误?不是错误?
答案 0 :(得分:2)
我不认为这是一个错误;你说的看起来更像是“COM伏都教”。在引擎盖下,C#编译器发出的事实上是正确的,如下所示:
private static void Foo(IFoo o)
{
...
Guid g = Guid.NewGuid();
Guid <>r__ComRefCallLocal0 = g;
Bar(o, ref <>r__ComRefCallLocal0);
...
}
事实上,C#充满了诡计。如果你向IFoo添加一个方法,例如
[ComImport, Guid("cb4ac859-0589-483e-934d-b27845d5fe74")]
interface IFoo
{
void Test([Optional] ref object test);
}
再次,您将能够在C#4中声明这一点:
static void Foo(IFoo o)
{
Guid g = Guid.NewGuid();
o.Test(g);
}
当然,所有这一切都有效,因为CSC.EXE对ComImport属性有深入的了解。这些新的魔术Interop技巧被添加到C#4.0中,以便能够轻松地与现有的COM接口互操作。好吧,对于Microsoft Office界面和方法,尤其是可怕的'ref missing'参数的军队: - )
我不认为这在任何地方都是完全指定的。这就是C#4规范所说的全部内容:
17.5互操作的属性注意:本节仅适用于C#的Microsoft .NET实现。 17.5.1与COM和Win32组件的互操作.NET运行时提供了大量支持C#程序的属性 与使用COM和Win32 DLL编写的组件互操作。对于 例如,DllImport属性可用于静态extern方法 表明该方法的实现是在a中找到的 Win32 DLL。这些属性可以在 System.Runtime.InteropServices命名空间和详细文档 这些属性可以在.NET运行时文档中找到。
以下是MSDN上的一些页面: