簡體   English   中英

在虛擬方法上使用 OpCodes.Call 是否安全?

[英]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它會被正確調用,即使從技術上講這個方法沒有在MyChildMyChild

我打算編寫一些代碼來遍歷類型層次結構到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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM