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

问题描述 投票:0回答:1

C# 4,为了简化 COM 互操作,允许 COM 接口的调用者在 by 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。并不是说我认为这会被修复,即使它被认为是一个错误,已经有代码依赖于此。

错误?不是bug吗?

c# c#-4.0 csc
1个回答
2
投票

我不认为这是一个错误;正如你所说,它看起来更像是“COM voodoo”。在幕后,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 属性有深入的了解。这些新的神奇互操作技巧被添加到 C# 4.0 中,以便能够轻松地与现有 COM 接口进行互操作。好吧,主要是针对 Microsoft Office 界面和方法,尤其是可怕的“引用丢失”参数大军:-)

我认为这在任何地方都没有完全指定。这就是 C# 4 规范的全部内容:

17.5 互操作属性 注意:本节仅适用于 C# 的 Microsoft .NET 实现。 17.5.1 与 COM 和 Win32 组件的互操作 .NET 运行时提供了大量属性,使 C# 程序能够 与使用 COM 和 Win32 DLL 编写的组件进行互操作。为了 例如,DllImport 属性可用于静态 extern 方法 表明该方法的实现可以在 Win32 DLL。这些属性可以在 System.Runtime.InteropServices命名空间和详细文档 这些属性可以在 .NET 运行时文档中找到。

以下是 MSDN 上的一些页面:

© www.soinside.com 2019 - 2024. All rights reserved.