[英]Clarify C# Extension Method Precedence
我正在嘗試通過創建自己的具有相同名稱的擴展方法來修改現有擴展方法的行為。 我知道這是可能的,只要方法簽名不同即可。 我也知道調用哪種方法取決於簽名的接近程度。
如果我有
public void DoStuff(this List<string> list) {
//...
}
和
public void DoStuff<T>(this List<T> list) {
//...
}
我知道DoStuff
將要求new List<string>().DoStuff()
而DoStuff<T>
將要求new List<int>().DoStuff()
我不明白的是為什么我在使用界面時看不到相同的行為。
public interface IBar { }
public class Foo : IBar
{
}
public static class FooHelper
{
public static void DoStuff(this IBar stuff)
{
Console.WriteLine("public static void DoStuff (this IBar stuff)");
}
public static void DoStuff<T>(this T stuff)
{
Console.WriteLine("public static void DoStuff<T>(this T stuff)");
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.DoStuff();
}
}
在上面的示例中,我期望將public static void DoStuff (this IBar stuff)
輸出到輸出,但是我得到了public static void DoStuff<T>(this T stuff)
。 我假設接口類型比泛型類型更具體,因此我的DoStuff
調用是更好的選擇。
為什么選擇通用類型簽名而不是接口類型簽名?
克里斯的評論是正確的,以下是C#語言規范中的更多詳細信息:
調用擴展方法foo.DoStuff()
等效於調用靜態方法FooHelper.DoStuff(foo)
。
編譯器必須確定要調用的確切方法(第7.6.5.1節方法調用)。 首先,它將創建一組候選方法。 這兩個DoStuff方法都將在此集合中,因為
o如果F是非泛型的,則在以下情況下F是候選者:
•M沒有類型參數列表,並且
•F適用於A(第7.5.3.1節)。
o如果F是泛型且M沒有類型參數列表,則在以下情況下F是候選值:
•類型推斷(第7.5.2節)成功,為調用推斷類型實參列表,並且
•一旦將推斷的類型參數替換為相應的方法類型參數,F的參數列表中的所有構造類型都將滿足其約束(第4.4.4節),並且F的參數列表適用於A(第7.5節)。 3.1)。
通用FooHelper.DoStuff
方法將具有推斷的類型參數(第7.5.2節):
類型推斷是方法調用(第7.6.5.1節)的綁定時處理的一部分,發生在調用的重載解決步驟之前。
如果類型推斷成功,則使用推斷的類型實參確定用於后續重載解析的參數類型。
所以候選集是
public static void DoStuff(this IBar stuff)
public static void DoStuff<Foo>(this Foo stuff)
從這個集合中,編譯器將選擇最佳的調用方法。 這些規則在第7.5.3.2節中進行了描述。 在這種情況下,將調用通用方法,因為身份轉換(從Foo到Foo)比從Foo到IBar的轉換更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.