[英]Is it safe to use OpCodes.Call on a virtual method?
我正在為屬性生成動態代理。
生成的代理源自我們要代理的類型。 當代理需要訪問其派生類型的(虛擬)屬性時,無法使用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
上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 是否安全?
您通常不需要聲明類型的實現。
大概您想要做與base
關鍵字對 C# 編譯器所做的相同的事情。 C# 編譯器實際上查找派生最多的父實現並直接調用它,但是您所做的也是完全合法的。
如果基類在另一個程序集中,它們有不同的行為,並且在代碼生成運行后重新編譯該程序集並添加新的覆蓋。 有關更多詳細信息,請參閱 Eric Lippert(C# 編譯器主要開發人員之一)撰寫的這篇博客文章,該文章解決了這個確切的場景:
這個問題說明了針對當前方法的OpCodes.Call
與具有實際實現的最派生父級之間的行為差異:
重申一下,您不想使用DeclaringType
的實現,這通常不是上述兩個合理選擇中的任何一個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.