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

时间:2018-01-07 18:47:34

标签: c# .net code-generation reflection.emit mono.cecil

我正在使用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

1 个答案:

答案 0 :(得分:0)

创建程序集:

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);
}

现在创建主类:

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”打印到标准输出