¿Cómo detecta el compilador de C# los tipos COM?
EDITAR: He escrito los resultados como una publicación de blog .
El compilador de C# trata los tipos COM de forma algo mágica. Por ejemplo, esta afirmación parece normal...
Word.Application app = new Word.Application();
... hasta que te das cuenta de que Application
es una interfaz. ¿Llamar a un constructor en una interfaz? ¡Yoiks! En realidad, esto se traduce en una llamada a Type.GetTypeFromCLSID()
y otra a Activator.CreateInstance
.
Además, en C# 4, puedes usar argumentos que no sean de referencia para ref
los parámetros, y el compilador simplemente agrega una variable local para pasar por referencia, descartando los resultados:
// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");
(Sí, faltan muchos argumentos. ¿No son buenos los parámetros opcionales? :)
Estoy intentando investigar el comportamiento del compilador y no logro falsificar la primera parte. Puedo hacer la segunda parte sin problema:
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
void Foo(ref int x);
}
class Test
{
static void Main()
{
Dummy dummy = null;
dummy.Foo(10);
}
}
Me gustaría poder escribir:
Dummy dummy = new Dummy();
aunque. Obviamente explotará en el momento de la ejecución, pero está bien. Sólo estoy experimentando.
Los otros atributos agregados por el compilador para COM PIA vinculados ( CompilerGenerated
y TypeIdentifier
) no parecen funcionar... ¿cuál es la salsa mágica?
De ninguna manera soy un experto en esto, pero recientemente me topé con lo que creo que quieres: la clase de atributo CoClass .
[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }
Una coclase proporciona implementaciones concretas de una o más interfaces. En COM, estas implementaciones concretas se pueden escribir en cualquier lenguaje de programación que admita el desarrollo de componentes COM, por ejemplo, Delphi, C++, Visual Basic, etc.
Vea mi respuesta a una pregunta similar sobre Microsoft Speech API , donde puede "crear una instancia" de la interfaz SpVoice
(pero en realidad, está creando una instancia SPVoiceClass
).
[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }
Entre Michael y tú casi habéis juntado las piezas. Creo que así es como funciona. (No escribí el código, por lo que podría estar expresándolo un poco mal, pero estoy bastante seguro de que así es como funciona).
Si:
- eres "nuevo" en un tipo de interfaz, y
- el tipo de interfaz tiene una coclase conocida, y
- ESTÁS usando la función "no pia" para esta interfaz
luego el código se genera como (IPIAINTERFACE)Activator.CreateInstance(Type.GetTypeFromClsid(GUID OF COCLASSTYPE))
Si:
- eres "nuevo" en un tipo de interfaz, y
- el tipo de interfaz tiene una coclase conocida, y
- NO ESTÁS utilizando la función "no pia" para esta interfaz
luego el código se genera como si hubieras dicho "nuevo COCLASSTYPE()".
Jon, no dudes en molestarnos a mí o a Sam directamente si tienes preguntas sobre este tema. Para su información, Sam es el experto en esta función.