【问题标题】:Is it safe to use OpCodes.Call on a virtual method?在虚拟方法上使用 OpCodes.Call 是否安全?
【发布时间】:2015-06-22 04:39:12
【问题描述】:

我正在为属性生成动态代理。

生成的代理派生自我们要代理的类型。 当代理需要访问其派生类型的(虚拟)属性时,OpCodes.Callvirt 无法使用 - 它会导致无限递归。因此我们需要调用OpCodes.Call。我注意到如果我有:

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

当我在从MyChild 派生的代理对象上发出OpCodes.Call 以调用get_Color 时,它会被正确调用,即使从技术上讲,此方法并未在MyChild 上实现。

我打算编写一些代码,将类型层次结构向下遍历到 MyParent,其中可以找到 get_Color 实现,并为 OpCodes.Call 使用该类型方法,但似乎没有必要这样做:

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

然后

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

不使用 declaringTypeMethod 而使用 thisTypeMethod 是否安全?

【问题讨论】:

    标签: c# .net reflection reflection.emit


    【解决方案1】:

    您通常不希望声明类型的实现。

    大概您想做与base 关键字对C# 编译器所做的相同的事情。 C#编译器其实是查找派生最多的父实现直接调用它,但是你所做的也是完全合法的。

    如果基类位于另一个程序集中,则它们具有不同的行为,并且在您的代码生成运行后重新编译该程序集并添加新的覆盖。有关详细信息,请参阅 Eric Lippert(C# 编译器主要开发人员之一)的这篇博客文章,该文章解决了这个确切场景:

    这个问题说明了OpCodes.Call 与当前方法之间的行为差​​异,以及具有实际实现的最派生父级:

    重申一下,您不想使用DeclaringType 中的实现,这通常不是上述两个合理选择中的任何一个。

    【讨论】:

      猜你喜欢
      • 2020-10-21
      • 2012-10-26
      • 1970-01-01
      • 2015-04-02
      • 1970-01-01
      • 2016-07-28
      • 1970-01-01
      • 2014-09-30
      • 2020-11-28
      相关资源
      最近更新 更多