Ошибка компилятора C # или обычная странность COM? - PullRequest
18 голосов
/ 19 января 2012

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. Поэтому я подал ошибку при подключении . Не то чтобы я думал, что это будет исправлено, даже если это будет считаться ошибкой, уже есть код, основанный на этом.

Ошибка? Не ошибка?

1 Ответ

2 голосов
/ 19 января 2012

Я не думаю, что это ошибка;это больше похоже на "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.Эти новые магические приемы взаимодействия были добавлены в C # 4.0, чтобы можно было легко взаимодействовать с существующими интерфейсами COM.Ну, в основном для интерфейсов и методов Microsoft Office, и особенно для множества ужасных параметров ref ref: -)

Я не думаю, что это где-то полностью указано.Это все, что говорится в спецификации C # 4:

17.5 Атрибуты для взаимодействия Примечание. Этот раздел применим только к реализации Microsoft CNET для C #.17.5.1 Взаимодействие с компонентами COM и Win32. Среда выполнения .NET предоставляет большое количество атрибутов, которые позволяют программам на C # взаимодействовать с компонентами, написанными с использованием библиотек DLL COM и Win32.Например, атрибут DllImport можно использовать в статическом методе extern, чтобы указать, что реализация метода находится в Win32 DLL.Эти атрибуты находятся в пространстве имен System.Runtime.InteropServices, а подробная документация по этим атрибутам содержится в документации по среде выполнения .NET.

А вот несколько страниц в MSDN:

...