8

I'm trying to implement this pattern using Reflection.Emit (TypeBuilder):

public class ClassToBeProxied
{
    public virtual object Property1 { get; set; }
}

public class Proxy : ClassToBeProxied
{
    [AttributeToBeAdded]
    public override object Property1
    {
        get
        {
            //do something else to return the object - i.e get it from the database
            return null; //stub
        }
        set
        {
            //do something else to set the object - i.e, save it to a database
        }
    }        
}

If all I were doing was intercepting the get and set methods, then this works:

PropertyInfo info = typeof(ClassToBeProxied).GetProperty("Property1", BindingFlags.Public | BindingFlags.Instance);
{
    MethodBuilder pGet = typeBuilder.DefineMethod("get_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, info.PropertyType, Type.EmptyTypes);
    ILGenerator pILGet = pGet.GetILGenerator();

    //The proxy object
    pILGet.Emit(OpCodes.Ldarg_0);
    //The database
    pILGet.Emit(OpCodes.Ldfld, database);
    //The proxy object
    pILGet.Emit(OpCodes.Ldarg_0);
    //The ObjectId to look for
    pILGet.Emit(OpCodes.Ldfld, f);
    pILGet.Emit(OpCodes.Callvirt, typeof(MongoDatabase).GetMethod("Find", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ObjectId) }, null).MakeGenericMethod(info.PropertyType));
    pILGet.Emit(OpCodes.Ret);

    MethodBuilder pSet = typeBuilder.DefineMethod("set_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new Type[] { info.PropertyType });
    ILGenerator pILSet = pSet.GetILGenerator();
    pILSet.Emit(OpCodes.Ldarg_0);
    pILSet.Emit(OpCodes.Ldarg_1);
    pILSet.Emit(OpCodes.Ldarg_0);
    pILSet.Emit(OpCodes.Ldfld, database);
    pILSet.Emit(OpCodes.Call, typeof(ProxyBuilder).GetMethod("SetValueHelper", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(MongoDatabase) }, null));
    pILSet.Emit(OpCodes.Stfld, f);
    pILSet.Emit(OpCodes.Ret);

    //Edit:  Added fix
    newProp.SetSetMethod(pSet);
    newProp.SetGetMethod(pGet);
}

But what I need to do is also add an attribute to the Property. I can't figure out how to do this.

If I add a new PropertyDefinition:

PropertyBuilder newProp = typeBuilder.DefineProperty(info.Name, PropertyAttributes.None, info.PropertyType, Type.EmptyTypes);
newProp.SetCustomAttribute(new CustomAttributeBuilder(typeof(AttributeToBeAdded).GetConstructor(Type.EmptyTypes), Type.EmptyTypes, new FieldInfo[0], new object[0]));

and then call GetProperties() on the generated type, two properties with the same name appear. However, if I build the code by hand (as in the example above), and call typeof(Proxy).GetProperties(), only one Property (the derived class property) is visible. This is the behavior I need, but I can't seem to get there with Reflection.Emit

Please let me know if I need to add more info to make the question clearer.

Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75
  • hi @Joe Enzminger, can you add in details what is the simplest way to override the getter method, the provided code is not complete and i'm finding some troubles understanding what you are doing in each step. Thanks – Hilmi Nov 17 '13 at 22:05
  • 1
    Take a look at [this](https://gist.github.com/joeenzminger/7526426) code snippet. – Joe Enzminger Nov 18 '13 at 11:39

1 Answers1

7

So the answer was add this:

newProp.SetSetMethod(pSet);
newProp.SetGetMethod(pGet);

See the edited question.

The answer kind of contradicts http://www.gutgames.com/post/Overridding-a-Property-With-ReflectionEmit/

but it seems to work.

deczaloth
  • 7,094
  • 4
  • 24
  • 59
Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75
  • thanks so much for that key is not define the property but only the get and set functions – oudi Apr 02 '20 at 07:52