2012-10-12 47 views
5

Ho il seguente codice C#:funzione di emissione con parametro opzionale

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

E qui si tratta di codice 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 

Come posso ottenere con System.Reflection.Emit o meglio con lo Mono.Cecil?

risposta

4

Se voglio fare cose con Mono.Cecil Generalmente creo una classe/metodo in C# con il codice previsto. Poi lo controllo (assicurati di averlo eseguito in modalità di rilascio) con Mono.Cecil e ricrearlo.

Quindi è necessario un MethodDefinition con un parametro name, attributes e returnType. Il nome: "f"

Gli attributi per il metodo potrebbe essere: Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.HideBySig

E il tipo di ritorno (di tipo Mono.Cecil.TypeReference come System.Double)

Per quanto riguarda i parametri, ci sono due ParameterDefinition si può aggiungere con target.Parameters.Add()

uno dei vostri parametri ha un valore di default in modo da suoi attributi devono essere Mono.Cecil.ParameterAttributes.Optional | Mono.Cecil.ParameterAttributes.HasDefault e la sua Constant insieme a 1.0 (nel tuo caso)

Ora per il corpo del metodo:

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

Dopo aver ispezionato le istruzioni da target.Body.Instructions, vediamo i seguenti codici:

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 

Quindi, basta aggiungere i codici nella giusta sequenza

processor.Append(OpCodes.Ldarg_0); 

Successivamente, iniettare/salvare il MethodDefinition al rispettivo gruppo.

mio codice assembly ispettore simile a questa:

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

non si dovrebbe mai essere necessario aggiungere "NOP". Se stai vedendo "nop", significa (invariabilmente) che hai costruito in modalità di debug piuttosto che in modalità di rilascio, prima di guardare il codice in reflector/isdasm/qualunque. Sarebbe molto meglio ispezionare l'IL da una build di rilascio. –

+0

@MarcGravell Grazie per l'attenzione! – Alex

+0

Non sapevo solo di impostare Constant come valore. Grazie lo stesso! –

Problemi correlati