2012-01-19 11 views
18

C# 4, para simplificar la interoperabilidad COM, permite a las personas que llaman a las interfaces COM omitir la palabra clave ref delante de los argumentos por los parámetros ref.¿Error del compilador C# o rareza COM normal?

Me sorprendió ver hoy que esto también se aplica a los métodos de extensión que amplían las interfaces COM. Véase el siguiente, la compilación, el código:

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

no he encontrado nada en la especificación para explicar este comportamiento.

Mi impresión sería que el código fuera de la interfaz COM, incluso si se trata de un método de extensión que amplía una interfaz COM, debería seguir las reglas normales de C# e imponer el uso de la palabra clave ref. Por lo tanto, presenté un bug on connect. No es que crea que esto se solucione, incluso si se considera un error, ya hay un código que se basa en esto.

Error? No es un error?

+3

muy interesante. La especificación 4.0 parece ser ambigua aquí.Dice que esto se aplica a los métodos de un tipo COM (sección 22 + 22.1). Pero no pude encontrar nada que explícitamente diga o no diga que un método de extensión se considera parte de un tipo de esta manera. Yo creo que es un error. Estoy seguro de que Eric llegará pronto para aclarar. – JaredPar

+11

Eso seguro suena como un error. Mi autobús todavía no está funcionando hoy debido a la lluvia helada sobre la nieve, por lo que estoy lejos de la oficina. Lo echaré un vistazo la próxima semana. Gracias por ingresar al problema en Connect! –

Respuesta

2

No creo que sea un error; se parece más a "COM vudú" como dices. Bajo el capó, el compilador de C# emite cosa que es de hecho correcta, así:

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

C# es, de hecho, lleno de trucos. Si se agrega un método para IFoo, así por ejemplo,

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

que, una vez más, será capaz de declarar esto en C# 4:

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

Por supuesto, todo esto sólo funciona porque CSC .EXE tiene un conocimiento íntimo del atributo ComImport. Estos nuevos trucos mágicos de Interop se agregaron a C# 4.0 para poder interoperar fácilmente con las interfaces COM existentes. Bueno, para las interfaces y los métodos de Microsoft Office en su mayoría, y especialmente para los ejércitos de los espantosos parámetros 'ref missing' :-)

No creo que esto esté completamente especificado en ninguna parte. Esto es todo lo que la especificación C# 4 tiene que decir:

17.5 Atributos para interoperación Nota: esta sección es aplicable solo a la implementación de Microsoft .NET de C#. 17.5.1 Interoperación con componentes COM y Win32 .NET run-time proporciona una gran cantidad de atributos que permiten que los programas C# interoperen con componentes escritos utilizando COM y Win32 DLL. Para el ejemplo , el atributo DllImport se puede usar en un método extern estático para indicar que la implementación del método se debe encontrar en una DLL Win32 . Estos atributos se encuentran en el espacio de nombres System.Runtime.InteropServices , y la documentación detallada para estos atributos se encuentra en la documentación de tiempo de ejecución de .NET.

Y aquí están algunas páginas en MSDN:

+2

Simon, sé que lo que el compilador emite es válido. También sé que los sitios de llamada del método de interfaz COM pueden omitir la referencia para los argumentos de un parámetro ref, pero esa no es la pregunta. La pregunta es saber si esto se aplica a los métodos de extensión, ya que no está especificado en la especificación. –

+0

No está tan claro lo que sabes y lo que no sabes de la pregunta. Intenté responder al "error o no". Creo que no es un * error * porque es la implementación de Microsoft .NET de C#, por lo que la implementación y los escenarios admitidos son exactamente lo que Microsoft decide que debe ser. –

+0

@SimonMourier, eso significaría que C# nunca podría tener ningún error, eso es una tontería. El compilador C# se rige por la especificación C#. Si el compilador y la especificación están en conflicto, eso significa que hay un error. Podría ser un error en el compilador o en la especificación y podría ser incluso deliberado, pero definitivamente es un error. – svick

Cuestiones relacionadas