dimanche 21 juin 2015

Is it safe to use OpCodes.Call on a virtual method?

I'm playing with generating dynamic proxies for properties.

A generated proxy is derived from a type that we want to proxy. When the proxy needs to access a (virtual) property on the type it's derived from, virtcall can't be used - it leads to infinite recursion. Thus we need to call OpCodes.Call. I noted that if I have:

public class MyParent 
{
    protected string _name;
    protected string _color;

    public virtual string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    public virtual string Color
    {
        get { return _color; }
        set { _color = value; }
    }
}

public class MyChild : MyParent
{
    public override string Name {
        get { return "42"; }
        set { _name = value; } 
    }
}

When I emit OpCodes.Call on the proxy object derived from MyChild to call get_Color it gets called correctly, even though technically this method is not implemented on MyChild.

I was going to write some code that traverses the type hierarchy down to MyParent where get_Color implementation can be found and using that type method for OpCodes.Call, but it appears this is not necessary:

var thisTypeMethod = property.GetGetMethod();
// I know that the next line technically is not correct because of non-virtual methods 
// and also *new* overrides. Assume I'm doing it correctly, not by property.Name 
// but by repeatedly calling MethodInfo.GetBaseDefinition()
var declaringTypeMethod = property.DeclaringType.GetProperty(property.Name).GetGetMethod();

and then

var proxyMethod = new DynamicMethod(thisTypeMethod.Name,thisTypeMethod.ReturnType, new Type[]{type},type,true);
var il = proxyMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, thisTypeMethod);
il.Emit(OpCodes.Ret);

Is it safe NOT using declaringTypeMethod and using thisTypeMethod instead?





Aucun commentaire:

Enregistrer un commentaire