我想使用单声道。塞西尔创建一个委托,但我不知道如何获得它的构造函数

I want to use Mono. Cecil to create a delegate, but I don't know how to get its constructor

我希望能够为代码生成 il

InjectBake.AddConstruction(typeof(Tests.TestConst), new Func<object[], IServiceProvider, object>[]
{
    Test1,
    Test2
});

我在反编译中看到这段代码,我不知道如何构造它,

newobj instance void class [mscorlib]System.Func`3<object[], class [mscorlib]System.IServiceProvider, object>::.ctor(object, native int)

假设您要生成以下 class:

using System;

class Test
{
    static string M(int i) { return i.ToString(); }
  
    void Foo()
    {
           Func conv = M;
    }
}

您可以使用Cecilifier生成以下代码:

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System; 
using System.Linq;
using BindingFlags = System.Reflection.BindingFlags;

using Cecilifier.Runtime;
               
public class SnippetRunner
{
    public static void Main(string[] args)
    {
        using(var assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("Test", Version.Parse("1.0.0.0")), "moduleName", ModuleKind.Dll))
        {
            var t1 = new TypeDefinition("", "Test", TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.NotPublic, assembly.MainModule.TypeSystem.Object);
            assembly.MainModule.Types.Add(t1);
            t1.BaseType = assembly.MainModule.TypeSystem.Object;
            var Test_ctor_ = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, assembly.MainModule.TypeSystem.Void);
            t1.Methods.Add(Test_ctor_);
            var il1 = Test_ctor_.Body.GetILProcessor();
            var Ldarg_02 = il1.Create(OpCodes.Ldarg_0);
            il1.Append(Ldarg_02);
            var Call3 = il1.Create(OpCodes.Call, assembly.MainModule.ImportReference(TypeHelpers.DefaultCtorFor(t1.BaseType)));
            il1.Append(Call3);
            var Ret4 = il1.Create(OpCodes.Ret);
            il1.Append(Ret4);
            

            //Method : M
            var Test_M_int32 = new MethodDefinition("M", MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.HideBySig, assembly.MainModule.TypeSystem.String);
            t1.Methods.Add(Test_M_int32);
            var il_Test_M_int32 = Test_M_int32.Body.GetILProcessor();

            //Parameters of 'static string M(int i) { return i.ToString(); }'
            var i5 = new ParameterDefinition("i", ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32);
            Test_M_int32.Parameters.Add(i5);

            //return i.ToString(); 
            var Ldarga6 = il_Test_M_int32.Create(OpCodes.Ldarga, i5);
            il_Test_M_int32.Append(Ldarga6);
            var Call7 = il_Test_M_int32.Create(OpCodes.Call, assembly.MainModule.ImportReference(TypeHelpers.ResolveMethod("System.Private.CoreLib", "System.Int32", "ToString",System.Reflection.BindingFlags.Default|System.Reflection.BindingFlags.Instance|System.Reflection.BindingFlags.Public,"")));
            il_Test_M_int32.Append(Call7);
            var Ret8 = il_Test_M_int32.Create(OpCodes.Ret);
            il_Test_M_int32.Append(Ret8);

            //Method : Foo
            var Test_Foo_ = new MethodDefinition("Foo", MethodAttributes.Private | MethodAttributes.HideBySig, assembly.MainModule.TypeSystem.Void);
            t1.Methods.Add(Test_Foo_);
            var il_Test_Foo_ = Test_Foo_.Body.GetILProcessor();

            //Func<int, string> conv = M;
            var lv_conv9 = new VariableDefinition(assembly.MainModule.ImportReference(typeof(System.Func<,>)).MakeGenericInstanceType(assembly.MainModule.TypeSystem.Int32,assembly.MainModule.TypeSystem.String));
            Test_Foo_.Body.Variables.Add(lv_conv9);
            var Ldnull10 = il_Test_Foo_.Create(OpCodes.Ldnull);
            il_Test_Foo_.Append(Ldnull10);
            var Ldftn11 = il_Test_Foo_.Create(OpCodes.Ldftn, Test_M_int32);
            il_Test_Foo_.Append(Ldftn11);
            var Newobj12 = il_Test_Foo_.Create(OpCodes.Newobj, assembly.MainModule.ImportReference(TypeHelpers.ResolveMethod("System.Private.CoreLib", "System.Func`2", ".ctor",System.Reflection.BindingFlags.Default|System.Reflection.BindingFlags.Instance|System.Reflection.BindingFlags.Public,"System.Int32,System.String", "System.Object", "System.IntPtr")));
            il_Test_Foo_.Append(Newobj12);
            var Stloc13 = il_Test_Foo_.Create(OpCodes.Stloc, lv_conv9);
            il_Test_Foo_.Append(Stloc13);
            var Ret14 = il_Test_Foo_.Create(OpCodes.Ret);
            il_Test_Foo_.Append(Ret14);

            PrivateCoreLibFixer.FixReferences(assembly.MainModule);
            assembly.Write(args[0]);
        }
    }
}

简单来说,您需要:

  1. 获取您要更改/添加代码的方法定义。 (第 48 行)

  2. 获取该方法的 ILProcessor(第 50 行)

  3. 注入 NewObj IL(第 59 行)

第 3 步是最重要的:

var Newobj12 = il_Test_Foo_.Create(
               OpCodes.Newobj,
               assembly.MainModule.ImportReference(
                   TypeHelpers.ResolveMethod(
                        "System.Private.CoreLib", 
                        "System.Func`2",
                        ".ctor",
                         System.Reflection.BindingFlags.Default|System.Reflection.BindingFlags.Instance|System.Reflection.BindingFlags.Public,
                        "System.Int32,System.String", 
                        "System.Object", 
                        "System.IntPtr")));
    

基本上它只是调用 ILProcessor.Create() 传递:

  1. 您要创建的操作码(指令)(在本例中为 Newobj)
  2. 对要实例化的对象的构造函数的引用。

对于上面的第 2 步,Cecilifier 使用辅助函数 TypeHelpers.ResolveMethod(),它基本上使用反射来检索方法并将其传递给 ModuleDefinition.ImportReference()