具有可选参数的发射功能

Iva*_*kin 5 .net c# il reflection.emit mono.cecil

我有以下C#代码:

public static double f(double x1, double x2 = 1)
{
    return x1 * x2;
}
Run Code Online (Sandbox Code Playgroud)

这里是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
Run Code Online (Sandbox Code Playgroud)

如何使用System.Reflection.Emit或更好的Mono.Cecil获取它?

Ale*_*lex 4

如果我想做一些事情,我通常会使用预期的代码Mono.Cecil创建一个类/方法。C#然后我检查它(确保您在发布模式下运行它)并Mono.Cecil重新创建它。

所以你需要一个MethodDefinition带有name,attributesreturnType参数。名字:“F”

您的方法的属性是:Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.HideBySig

和返回类型(类型Mono.Cecil.TypeReferenceSystem.Double

至于参数,有两个ParameterDefinition你可以添加target.Parameters.Add()

您的参数之一具有默认值,因此其属性必须为Mono.Cecil.ParameterAttributes.Optional | Mono.Cecil.ParameterAttributes.HasDefault 并且Constant设置为1.0(在您的情况下)

现在是方法体:

target.Body.GetILProcessor();  // target is your `MethodDefinition` object.
Run Code Online (Sandbox Code Playgroud)

检查指令后target.Body.Instructions,我们看到以下代码:

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
Run Code Online (Sandbox Code Playgroud)

所以只需按正确的顺序添加代码即可

 processor.Append(OpCodes.Ldarg_0);
Run Code Online (Sandbox Code Playgroud)

之后,将您的注入/保存MethodDefinition到相应的程序集中。

我的程序集检查器代码如下所示:

 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());
                        }
                    }
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • 你永远不需要添加“nop”。如果您看到“nop”,则意味着(总是)您在查看 Reflector/isdasm/其他内容中的代码之前以调试模式而不是发布模式构建。从发布版本中检查 IL 会更好。 (5认同)