使用Reflection.Emit从另一个对象获取属性值

时间:2012-12-21 13:18:14

标签: .net reflection.emit

这是我第一次尝试使用Reflection.Emit。我正在为提供的对象动态构建代理。代理将任何公共属性访问传递给提供的对象。我收到的错误是:

  

对象'ProxyObject'上的属性访问者'AccessorName'引发了以下异常:   尝试通过方法'ProxyObject.get_AccessorName()'来访问方法   'NS.CoreObject.get_AccessorName()失败。

从我可以假设和收集的内容来看,这可能是由于自动生成的属性getter方法是私有的和隐藏的。但是,如何使用MethodBuilder

解决此问题

根据Create DynamicMethod to assign value to a property?的帖子,您可以通过声明方法与目标模块“关联”来使用DynamicMethod来完成,但我需要构建一个完整的类。是否可以通过Reflection.Emit实现等效的“关联”?

这是我正在尝试执行的一项基本操作,因此我确信这是一些我不知道的直接和简单的事情。

1 个答案:

答案 0 :(得分:9)

使用MethodBuilder:你不能。您遵守通常的可访问性规则。但是,您可以通过DynamicMethod作弊,这允许您假装(如果您有足够的访问权限)您正在创建的方法实际上是给定类型的静态方法 (或给定模块等)。这意味着您可以自由访问私有状态,例如:

using System;
using System.Reflection;
using System.Reflection.Emit;

public class Foo
{
    public Foo(int bar)
    {
        Bar = bar;
    }
    private int Bar { get; set; }
}
static class Program {
    static void Main()
    {
        var method = new DynamicMethod("cheat", typeof(int),
            new[] { typeof(object) }, typeof(Foo), true);
        var il = method.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, typeof(Foo));
        il.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("Bar",
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
            ).GetGetMethod(true));
        il.Emit(OpCodes.Ret);
        var func = (Func<object, int>)method.CreateDelegate(
            typeof(Func<object, int>));

        var obj = new Foo(123);
        Console.WriteLine(func(obj));
    }
}

如果您获取属性的值,还应注意Delegate.CreateDelegate可以通过getter方法自动执行相同的操作:

var method = typeof(Foo).GetProperty("Bar",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
    .GetGetMethod(true);
var func = (Func<Foo, int>)
    Delegate.CreateDelegate(typeof(Func<Foo, int>), method);