C#编译器错误还是正常的COM奇怪?

时间:2012-01-19 16:59:28

标签: c# c#-4.0 compiler-construction csc

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。并不是说我认为这将被修复,即使它被视为一个错误,那里已经有代码依赖于此。

错误?不是错误?

1 个答案:

答案 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上的一些页面: