简体   繁体   English

Reflection.Emit - IL - 对象的调用方法

[英]Reflection.Emit - IL - call method on object

I'm working on creating a dynamic method at runtime to copy an object. 我正在努力在运行时创建一个动态方法来复制一个对象。 Lets assume: 让我们假设:

class Source
{
   public List<int> L1 {get;set;}
}

class Dest
{
   public List<int> L1 {get;set;}
}

Now, this situation works correctly. 现在,这种情况正常。 I get Source.L1 and I set Dest.L1. 我得到Source.L1,然后设置Dest.L1。 I do so with the following IL: 我使用以下IL执行此操作:

        generator.Emit(OpCodes.Newobj, constructor);
        generator.Emit(OpCodes.Dup);
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Callvirt, miGetter);
        generator.Emit(OpCodes.Callvirt, miSetter);
        generator.Emit(OpCodes.Ret);

All this is working fine... now comes the tricky part. 所有这一切都很好......现在是棘手的部分。 Lets change Dest to: 让我们改变目的地:

class Dest
{
   private List<int> _l1 = new List<int>();
   public List<int> L1 {get { return _l1; } }
}

Now what I want to do in this case is call Dest.L1.Clear() and then Dest.L1.AddRange(...). 现在我想要做的是调用Dest.L1.Clear()然后调用Dest.L1.AddRange(...)。

I can't even get the .Clear to work. 我甚至无法让.Clear工作。

I still will have: 我仍然会:

        generator.Emit(OpCodes.Newobj, constructor);

        // this block is repeated 5 times for various properties

        generator.Emit(OpCodes.Dup);
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Callvirt, miGetter);
        generator.Emit(OpCodes.Callvirt, miSetter);

        // List property will be copied here
        // miGetter = Dest.L1.Get
        // TODO
        // end list property

        generator.Emit(OpCodes.Ret);

How do I need to set up the IL in the TODO block? 如何在TODO块中设置IL? I tried doing dup/loadArg0/call miGetter/call miClear, but that gave me an invalid program. 我尝试过dup / loadArg0 / call miGetter / call miClear,但这给了我一个无效的程序。

Here is a working example with an explanation of what happens to the evaluation stack on each step: 这是一个工作示例,解释了每个步骤中评估堆栈的情况:

DynamicMethod method =
    new DynamicMethod("Test", typeof(Dest), new Type[] { typeof(Source) });

var generator = method.GetILGenerator();

var constructor = typeof(Dest).GetConstructor(Type.EmptyTypes);

var miGetter = typeof(Source).GetProperty("L1").GetMethod;

var miDestGetter = typeof(Dest).GetProperty("L1").GetMethod;

var addRange = typeof(List<int>).GetMethod("AddRange");

var clear = typeof(List<int>).GetMethod("Clear");

generator.Emit(OpCodes.Newobj, constructor);//Stack: DestObject

generator.Emit(OpCodes.Dup);//Stack: DestObject,DestObject

generator.Emit(OpCodes.Call, miDestGetter);//Stack: DestObject,DestObject.L1

generator.Emit(OpCodes.Dup);//Stack: DestObject,DestObject.L1,DestObject.L1

generator.Emit(OpCodes.Call, clear);//Stack: DestObject,DestObject.L1

generator.Emit(OpCodes.Ldarg_0);//Stack: DestObject,DestObject.L1,SourceObject

generator.Emit(OpCodes.Call, miGetter);//Stack: DestObject,DestObject.L1,SourceObject.L1

generator.Emit(OpCodes.Call, addRange);//Stack: DestObject

generator.Emit(OpCodes.Ret);

var function = (Func<Source, Dest>)method.CreateDelegate(typeof(Func<Source, Dest>));

Source source = new Source
{
    L1 = new List<int>() { 1, 2, 3 }
};

var result = function(source);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM