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

标签 c# .net reflection compiler-construction emit

我正致力于在运行时创建一个动态方法来复制一个对象。让我们假设:

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

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

现在,这种情况可以正常工作。我得到 Source.L1 并设置 Dest.L1。我使用以下 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);

所有这一切都工作正常......现在是棘手的部分。让我们将 Dest 更改为:

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

在这种情况下,现在我想做的是调用 Dest.L1.Clear(),然后调用 Dest.L1.AddRange(...)。

我什至无法获得 .Clear 来工作。

我还会有:

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

我需要如何在 TODO block 中设置 IL?我尝试执行 dup/loadArg0/call miGetter/call miClear,但这给了我一个无效的程序。

最佳答案

这是一个工作示例,其中解释了评估堆栈在每个步骤中发生的情况:

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

关于c# - Reflection.Emit - IL - 对象上的调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36487863/

相关文章:

python - 如何获得谁调用了函数或方法?

c# - 带有 TPH 和枚举的 Entity Framework 中的多个 CASE WHEN

c# - 避免不同类中使用的相似背景 worker 的代码重复

.net - 如何编辑Azure管道中的应用程序设置?

c# - 无法识别捕获组的 RegEx

java - 如何检查方法是否使用反射声明?

c# - typeof() 有效,GetType() 在检索属性时无效

c# - 为什么这个运行时动态绑定(bind)会失败?

c# - 检测 ActiveSelf 的事件

c# - 如何在xamarin表单中设置选择器的值