我在玩为属性生成动态代理。
生成的代理来自我们希望代理的类型。当代理需要访问它派生的类型上的(虚拟)属性时,不能使用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派生的代理对象上发出MyChild以调用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安全吗?
发布于 2015-06-22 05:14:24
您通常不希望声明类型中的实现。
想必您希望做与base关键字在C#编译器中所做的相同的事情。C#编译器实际上查找最派生的父实现并直接调用它,但是您所做的也是完全合法的。
如果基类位于另一个程序集中,则它们具有不同的行为,并且在代码生成运行后重新编译该程序集,添加新的重写。有关更多细节,请参阅Eric ( C#编译器主要开发人员之一)的这篇博客文章,其中讨论了这个确切的场景:
这个问题说明了针对当前方法的OpCodes.Call与具有实际实现的派生最多的父级之间的行为差异:
重申一下,您不希望在DeclaringType中使用该实现,这通常不是上述两种合理选择中的一种。
https://stackoverflow.com/questions/30972209
复制相似问题