从动态创建的调用构造函数和方法 类

Call constructors and methods from dynamically created classes

我正在使用 Cecil 创建动态程序集。如何在发出操作码时调用其构造函数或方法?

class Test
{
    public static void Main(string[] args)
    {
        System.Console.WriteLine(new SomeClass().SomeMethod());
    }
}

class SomeClass
{
    public int SomeMethod() { return 0; }
}

如您所见,我需要 2 条 WriteLine 方法说明 - OpCodes.NewobjOpCodes.Call:

var assembly = AssemblyDefinition.CreateAssembly ( ... );
...
var mainMethod = new MethodDefinition( ... );
var ilProcessor = mainMethod.Body.GetILProcessor();
...
ilProcessor.Create(
    OpCodes.Newobj,
    assembly.MainModule.ImportReference(/* typeof("SomeClass") */
        .GetConstructor(Type.EmptyTypes)));

ilProcessor.Create(
    OpCodes.Call,
    assembly.MainModule.ImportReference(/* typeof("SomeClass") */
        .GetMethod("SomeMethod", Type.EmptyTypes)));

我该怎么做才能模仿 typeof("SomeClass") 调用 GetConstructorGetMethod

创建程序集:

var moduleName = "Test.exe";
var assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition(moduleName, new Version(1, 0, new Random().Next(1000))), moduleName, ModuleKind.Console);
var module = assembly.MainModule;

创建第一个类型:

TypeDefinition someClass;
MethodDefinition someMethod;
{
    someClass = new TypeDefinition("ConsoleDemo", "SomeClass", TypeAttributes.Class | TypeAttributes.Public, module.TypeSystem.Object);
    someMethod = new MethodDefinition("SomeMethod", MethodAttributes.Public, module.TypeSystem.Int32);
    someMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
    someMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
    someClass.Methods.Add(someMethod);

    var someClassCtor = new MethodDefinition(".ctor", MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, module.TypeSystem.Void);
    someClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
    someClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, objCtor));
    someClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
    someClass.Methods.Add(someClassCtor);

    module.Types.Add(someClass);
}

现在创建主class:

var testClass = new TypeDefinition("ConsoleDemo", "Test", TypeAttributes.Class | TypeAttributes.Public, module.TypeSystem.Object);
var mainMethod = new MethodDefinition("Main", MethodAttributes.Public | MethodAttributes.Static, module.TypeSystem.Void);
mainMethod.Parameters.Add(new ParameterDefinition("args", ParameterAttributes.None, new ArrayType(module.TypeSystem.String)));
var writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
var importedMethod = module.Import(writeLineMethod);
mainMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Newobj, someClass.GetConstructors().First()));
mainMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Call, someMethod));
mainMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Call, importedMethod));
mainMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
testClass.Methods.Add(mainMethod);

var mainClassCtor = new MethodDefinition(".ctor", MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, module.TypeSystem.Void);
mainClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
mainClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, objCtor));
mainClassCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
testClass.Methods.Add(mainClassCtor);
module.Types.Add(testClass);

不要忘记设置入口点:

module.EntryPoint = mainMethod;

现在可以保存了:

assembly.Write(moduleName);

在 运行 之后,它按预期将“0”打印到标准输出