2012-10-12 147 views
5

Tengo el siguiente código C#:que emite la función con el parámetro opcional

public static double f(double x1, double x2 = 1) 
{ 
    return x1 * x2; 
} 

Y aquí está el código IL (ILSpy):

.method public hidebysig static 
    float64 f (
     float64 x1, 
     [opt] float64 x2 
    ) cil managed 
{ 
    .param [2] = float64(1) 
    // Method begins at RVA 0x20c6 
    // Code size 4 (0x4) 
    .maxstack 8 

    IL_0000: ldarg.0 
    IL_0001: ldarg.1 
    IL_0002: mul 
    IL_0003: ret 
} // end of method A::f 

¿Cómo se puede conseguir con System.Reflection.Emit o mejor con Mono.Cecil?

Respuesta

4

Si quiero hacer cosas con Mono.Cecil generalmente creo una clase/método en C# con el código esperado. Luego lo inspecciono (asegúrese de ejecutarlo en modo Release) con Mono.Cecil y lo vuelvo a crear.

Así que necesitaría un MethodDefinition con un parámetro name, attributes y returnType. El nombre: "f"

Los atributos para el método sería: Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.HideBySig

Y el tipo de retorno (de tipo Mono.Cecil.TypeReference como System.Double)

En cuanto a los parámetros, hay dos ParameterDefinition que pueda añadir con target.Parameters.Add()

Uno de los parámetros tiene un valor por defecto por lo que sus atributos deben ser Mono.Cecil.ParameterAttributes.Optional | Mono.Cecil.ParameterAttributes.HasDefault y su Constant conjunto de 1.0 (en su caso)

ya por el cuerpo del método:

target.Body.GetILProcessor(); // target is your `MethodDefinition` object. 

Después de inspeccionar las instrucciones de target.Body.Instructions, vemos los siguientes códigos:

IL_0000: ldarg.0 
IL_0001: ldarg.1 
IL_0002: mul 
IL_0003: stloc.0 
IL_0004: br.s IL_0007 
IL_0005: ldloc.0 
IL_0007: ret 

Entonces sólo tiene que añadir los códigos en la secuencia correcta

processor.Append(OpCodes.Ldarg_0); 

Después de eso, inyecte/guarde su MethodDefinition al conjunto respectivo.

Mi ensamblaje Inspector de código es como la siguiente:

private static void EnumerateAssembly(AssemblyDefinition assembly) 
     { 
      foreach (var module in assembly.Modules) 
      { 
       foreach (var type in module.GetAllTypes()) 
       { 
        foreach (var field in type.Fields) 
        { 
         Debug.Print(field.ToString()); 
        } 
        foreach (var method in type.Methods) 
        { 
         Debug.Print(method.ToString()); 
         foreach (var instruction in method.Body.Instructions) 
         { 
          Debug.Print(instruction.ToString()); 
         } 
        } 
       } 
      } 
     } 
+5

nunca debería ser necesario añadir "nop". Si está viendo "nop", significa (invariablemente) que creó el modo de depuración en lugar del modo de lanzamiento, antes de mirar el código en reflector/isdasmo/lo que sea. Sería mucho mejor inspeccionar el IL desde una versión de lanzamiento. –

+0

@MarcGravell ¡Gracias por el aviso! – Alex

+0

No sabía solo acerca de establecer Constant para valorar. ¡Gracias de todos modos! –

Cuestiones relacionadas