Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get property value from another object using Reflection.Emit

This is my first foray into using Reflection.Emit. I'm dynamically building a proxy for a provided object. The proxy passes any public property accesses through to the provided object. The error I'm receiving is:

Property accessor 'AccessorName' on object 'ProxyObject' threw the following exception: Attempt by method 'ProxyObject.get_AccessorName()' to access method 'NS.CoreObject.get_AccessorName() failed.

From what I can assume and gather, this would be due to the automatically-generated property getter method being private and hidden. But how do I work around this using a MethodBuilder?

According to the post at Create DynamicMethod to assign value to a property?, you can do it with a DynamicMethod by declaring the method to be "associated" with the target module, but I need to build a full class. Is there an equivalent "association" that can be achieved through Reflection.Emit?

This is a basic operation I'm trying to perform, so I'm certain that it's something straight-forward and simple that I'm unaware of.

like image 882
redman Avatar asked Dec 21 '12 13:12

redman


1 Answers

With MethodBuilder: you cannot. You are subject to the usual rules of accessibility. You can, however, cheat via DynamicMethod, which allows you to pretend (if you have enough access) that the method you are creating is actually a static method of a given type (or a given module, etc). This means you can freely access private state, for example:

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

If you are only obtaining the value of the property, it should also be noted that Delegate.CreateDelegate can do the same automatically, via the getter method:

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);
like image 196
Marc Gravell Avatar answered Nov 15 '22 05:11

Marc Gravell