5

I have the following C# code:

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

And here it's IL code (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

How can I get it with System.Reflection.Emit or better with the Mono.Cecil?

Ivan Kochurkin
  • 4,413
  • 8
  • 45
  • 80

1 Answers1

4

If I want to do stuff with Mono.Cecil I usually create a class / method in C# with the expected code. I then inspect it (Make sure you're running it in Release mode) with Mono.Cecil and re-create it.

So you'd need a MethodDefinition with a name, attributes and returnType parameter. The name: "f"

The attributes for your method would be : Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.HideBySig

And the return type (of type Mono.Cecil.TypeReference as System.Double )

As for the parameters, there are two ParameterDefinition you can add with target.Parameters.Add()

One of your parameters has a default value so its attributes must be Mono.Cecil.ParameterAttributes.Optional | Mono.Cecil.ParameterAttributes.HasDefault and its Constant set to 1.0 (In your case)

Now for the method body:

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

After inspecting the instructions from target.Body.Instructions, we see the following codes :

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

So just add the codes in the right sequence

 processor.Append(OpCodes.Ldarg_0);

After that, inject / save your MethodDefinition to the respective assembly.

My assembly inspector code looks something like this:

 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());
                        }
                    }
                }
            }
        }
Alex
  • 7,901
  • 1
  • 41
  • 56
  • 5
    you should never need to add "nop". If you're seeing "nop", it means (invariably) you built in debug mode rather than release mode, prior to looking at the code in reflector/isdasm/whatever. It would be be much better to inspect the IL from a release build. – Marc Gravell Oct 12 '12 at 09:16
  • I did not know only about setting Constant to value. Thank you anyway! – Ivan Kochurkin Oct 12 '12 at 10:47