5

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.

Community
  • 1
  • 1
redman
  • 1,510
  • 17
  • 33
  • That's MethodAccessException. It sure sounds like the property is not in fact public. Make this work in C# first, the IL you get from it will be very helpful in your emit code as well. – Hans Passant Dec 21 '12 at 14:14
  • Of course, a public property means nothing when your class is not public. In my head, this type was being defined within the same module. Yet another *"I wasted hours on this?"* moment. – redman Dec 21 '12 at 15:00

1 Answers1

9

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);
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Makes sense (and is creative, too). If I'm building up a type via TypeBuilder, am I able to get the IL generated by your answer into the TypeBuilder-built type? Or are the two mutually exclusive? – redman Dec 21 '12 at 13:54
  • @redman getting the same IL wouldn't help. TypeBuilder is *still* restricted to standard accessibility. At the IL level you can *ask* for just about **anything**: it will still be checked at first use. – Marc Gravell Dec 21 '12 at 13:57
  • I just realized that part of my question was ambiguous. The properties I'm trying to access are *public*. It's the automatically-generated accessors that are not. (I've updated my question to reflect this.) So with that consideration, is it easier to make use of a property of another object through MethodBuilder? – redman Dec 21 '12 at 14:09
  • While the answer did not answer my intended question, it answered the perceived question based on an ambiguous framing. For this, you must get the credit. Now I at least know a trick for future use. – redman Dec 21 '12 at 15:01
  • @redman if the property accessor is public, it should just work – Marc Gravell Dec 21 '12 at 16:37