2012-01-19 19 views
18

C# 4, aby uprościć współdziałanie COM, zezwól wywołującym na interfejsy COM, aby pominąć słowo kluczowe ref przed argumentami dla parametrów ref.Błąd kompilatora C# lub normalne zdarzenie COM?

Zaskoczyło mnie, że dzisiaj dotyczy to również metod rozszerzających, które rozszerzają interfejsy COM. Zobacz poniższy kod, kompilacja:

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); 
    } 
} 

Nie znalazłem nic w specyfikacji, aby wyjaśnić to zachowanie.

Mam wrażenie, że kod poza interfejsem COM, nawet jeśli jest to metoda rozszerzająca rozszerzająca interfejs COM, powinien być zgodny z normalnymi regułami C# i wymuszać użycie słowa kluczowego ref. Dlatego też złożyłem wniosek o wydanie bug on connect. Nie sądzę, że to się naprawi, nawet jeśli zostanie to uznane za błąd, ale istnieje już kod, który polega na tym.

Błąd? Nie błąd?

+3

Bardzo interesująca. Specyfikacja 4.0 wydaje się tutaj niejednoznaczna.Mówi się, że dotyczy to metod typu COM (rozdział 22 + 22.1). Ale nie mogłem znaleźć niczego, co wyraźnie mówi lub nie mówi, że metoda rozszerzenia jest uważana za część typu w ten sposób. Zgaduję, że to błąd. Jestem pewien, że Eric wkrótce będzie z nami, żeby wyjaśnić. – JaredPar

+11

To z pewnością brzmi jak błąd. Mój autobus nadal nie działa dzisiaj z powodu mroźnego deszczu nad śniegiem, więc jestem z dala od biura. Przyjrzę się temu w przyszłym tygodniu. Dziękujemy za zgłoszenie problemu w serwisie Connect! –

Odpowiedz

2

Nie sądzę, że to błąd; wygląda bardziej jak "COM voodoo", jak mówisz. Pod maską # kompilator C emituje coś, co w rzeczywistości jest poprawna, na przykład:

private static void Foo(IFoo o) 
{ 
    ... 
    Guid g = Guid.NewGuid(); 
    Guid <>r__ComRefCallLocal0 = g; 
    Bar(o, ref <>r__ComRefCallLocal0); 
    ... 
} 

C# jest w rzeczywistości pełen sztuczek. Jeśli dodać metodę IFoo, jak to na przykład

[ComImport, Guid("cb4ac859-0589-483e-934d-b27845d5fe74")] 
interface IFoo 
{ 
    void Test([Optional] ref object test); 
} 

ty znowu będą mogli zadeklarować to w C# 4:

static void Foo(IFoo o) 
{ 
    Guid g = Guid.NewGuid(); 
    o.Test(g); 
} 

Oczywiście, wszystko to działa tylko dlatego, CSC .EXE ma doskonałą znajomość atrybutu ComImport. Te nowe magiczne sztuczki Interop zostały dodane do C# 4.0, aby móc łatwo współdziałać z istniejącymi interfejsami COM. Cóż, głównie dla interfejsów i metod Microsoft Office, a zwłaszcza dla armii o strasznych parametrach "brakujących" :-)

Nie sądzę, że jest to w pełni określone w dowolnym miejscu. To wszystko, co ma do powiedzenia specyfikacja C# 4:

17.5 Atrybuty do współdziałania Uwaga: Ta sekcja ma zastosowanie tylko do implementacji C# w Microsoft .NET. 17.5.1 Współdziałanie z komponentami COM i Win32. Czas uruchamiania .NET zapewnia dużą liczbę atrybutów, które umożliwiają programom C# współdziałanie ze składnikami napisanymi przy użyciu bibliotek DLL COM i Win32. W przypadku przykładu atrybut DllImport może być używany w statycznej metodzie zewnętrznej , aby wskazać, że implementację metody można znaleźć w bibliotece DLL Win32 Win32. Atrybuty te można znaleźć w przestrzeni nazw System.Runtime.InteropServices , a szczegółową dokumentację dla tych atrybutów można znaleźć w dokumentacji środowiska wykonawczego .NET.

A oto kilka stron na MSDN:

+2

Simon, wiem, że to, co wydobywa kompilator, jest poprawne. Wiem również, że strony wywołania metody interfejsu COM mogą pomijać argumenty ref dla parametru ref, ale to nie jest pytanie. Pytanie brzmi, czy dotyczy to metod rozszerzenia, ponieważ nie jest to określone w specyfikacji. –

+0

Nie jest jasne, co wiesz i czego nie wiesz na podstawie tego pytania. Próbowałem odpowiedzieć na "błąd lub nie błąd". Wierzę, że to nie jest * błąd *, ponieważ jest to implementacja Microsoft .NET C#, więc implementacja i obsługiwane scenariusze są właśnie tym, co Microsoft decyduje, że musi to być. –

+0

@SimonMourier, oznaczałoby to, że C# nie może mieć żadnych błędów, to nonsens. Kompilator C# jest sterowany przez specyfikację C#. Jeśli kompilator i specyfikacja są w konflikcie, oznacza to, że istnieje błąd. Może to być błąd w kompilatorze lub w specyfikacji i może być nawet celowy, ale na pewno jest to błąd. – svick

Powiązane problemy