2009-12-16 17 views
21

Los inicializadores de módulo son una característica del CLR que no están disponibles directamente en C# o VB.NET. Son métodos estáticos globales llamados .cctor que se garantiza que se ejecutarán antes de que se ejecute cualquier otro código (inicializadores de tipo, constructores estáticos) en un ensamblaje. Hace poco quería utilizar esto en un proyecto y hacked together my own solution (console program/msbuild task) usando Mono.Cecil, pero me preguntaba:Iniciales del módulo en C#

  1. ¿Hay alguna manera de engañar al compilador de C# en emitiendo intializers módulo? ¿Algún atributo (por ejemplo, CompilerGenerated, SpecialName) u otro truco que se pueda usar?

  2. ¿Los C#/VB.NET alguna vez emiten estos inicializadores por algún motivo? Por lo que he visto, C++ administrado los usa para algunos propósitos de interoperabilidad, pero no pude encontrar ninguna referencia a que se usen para otros fines. ¿Algunas ideas?

+1

Puede utilizar una técnica similar a la [Biblioteca de Melke Squeeze sin restricciones] (http://code.google.com/p/unconstrained-melody/), que utiliza para eludir el hecho de que no puede usar restricciones enum en C#. Su solución es usar atributos de marcador de posición para conducir un programa posterior al proceso (escrito en C#) que impulsa ilasm.exe para volver a escribir el IL para implementar correctamente las cosas que no se pueden implementar en C#. –

+0

Discusión relacionada: http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx – user423430

Respuesta

8

No, no hay forma de emitirlos en C#, porque C# pone todo en una clase/estructura y los inicializadores de módulos deben ser globales.

Deberá usar una herramienta diferente para escribirlas, preferiblemente IL-Assembler.

En cuanto a la segunda pregunta, tengo que admitir que no sé, pero nunca he visto ninguna generada por C#, y uso ILDasm con bastante frecuencia, así que supongo que no las emite.

-5

Si tiene constructores estáticos o clases singleton a las que puede acceder con una variable estática, el compilador C# emitirá .cctor.

+1

Emite un .cctor en la clase donde definió un constructor estático, sí, pero ese es solo el constructor estático de esa clase y se ejecutará la primera vez que se acceda a la clase. Un inicializador de módulo es un .cctor en la clase pseudo y se garantiza que se ejecutará antes que CUALQUIER otro código en el ensamblado, independientemente de qué código se acceda primero. –

3

Tal vez System.Reflection.Emit espacio de nombres puede ayudarlo. La enumeración MethodAttributes contiene elementos similares (SpecialName, RTSpecialName).

10

Salida del complemento módulo de inicialización de la impresionante código abierto del proyecto de IL-Weaver "fody", escrito por Simone Cropp: https://github.com/fody/moduleinit

Se le permite especificar un método que se traduce en un inicializador de montaje por fody:

public static class ModuleInitializer 
{ 
    public static void Initialize() 
    { 
     //Init code 
    } 
} 

consigue esto:

static <Module>() 
{ 
    ModuleInitializer.Initialize(); 
} 
+5

Gracias por la sugerencia. De hecho, se basa en mi propio código que escribí después de hacer esta pregunta. Simon Cropp luego lo adaptó como un complemento para su excelente proyecto Fody. –

1

Einar, Su questi no me dejó claro que ya escribió una herramienta que permite inyectar un inicializador de módulo en un ensamblado ya compilado.

http://einaregilsson.com/module-initializers-in-csharp

he intentado su aplicación y funciona perfectamente. Mientras escribe, debería funcionar con todos los marcos actuales de 2 a 4.5.

Solo hay un problema que hace que su solución sea inútil para mí: Se invoca su inicializador cuando la aplicación primero ACCEDE a cualquier cosa en el ensamblaje.

Lo que necesito es que se llame inmediatamente al inicializador del módulo cuando se carga el ensamblado en el proceso. Pero no lo es. Entonces, si la aplicación no accede al ensamblaje, nunca se inicializará.

Después de investigar todo un día, me parece que la única forma de obtener esto es escribir un ensamblado de C++ administrado y ejecutar el código en DllMain().

+0

. Los ensamblados .NET suelen estar cargados con retraso. Significado: su suposición de que el inicializador del módulo se ejecuta algún tiempo después de que se cargue el ensamblado probablemente no sea cierto. Es solo que el ensamblaje solo se carga cuando es necesario, * no * inmediatamente cuando se inicia la aplicación. –

+0

Quizás no fui lo suficientemente claro. Estoy hablando de cargar una DLL de C# en un proceso de C# a través de Assembly.Load(). En este caso, el inicializador no se ejecuta. Estaba buscando un equivalente para DllMain() en C++ que se ejecuta inmediatamente cuando el archivo DLL se carga en el proceso. – Elmue

+0

Ah, ya veo. Eso es extraño entonces. –

Cuestiones relacionadas