【问题标题】:Call constructors and methods from dynamically created classes从动态创建的类中调用构造函数和方法
【发布时间】:2018-06-16 20:23:36
【问题描述】:

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

【问题讨论】:

  • 创建动态类型后,您是否无法访问TypeInfo? (我通常为此使用TypeBuilder,而TypeBuilder 让您使用.CreateType() 来获得可以与ILGenerator 一起使用的TypeInfo,或者您可以传入TypeBuilder 本身作为它 TypeInfo - 只是不是RuntimeTypeInfo)
  • @MarcGravell 我会用 Cecil TypeDefinition 试试你的建议,这类似于 Reflection.Emit TypeBuilder

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


【解决方案1】:

创建程序集:

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

【讨论】:

    猜你喜欢
    • 2012-04-22
    • 2018-09-25
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 2011-03-24
    相关资源
    最近更新 更多