[英]Generic extension methods in C#: what will happen in this edge case?
在我最近的一個問題中,我了解到如果有多個擴展方法具有與給定類型匹配的約束,則將選擇最具體的擴展方法。 這讓我思考 - 編譯器如何確定哪一個“更具體”? 結果會是什么?
假設我有以下課程:
public MyClass : IComparable, IDisposable
{
// Implementation of members
}
public static class MyExtensions
{
public static void DoSomething<T>(this T item)
where T : IComparable
{ /* whatever */ }
public static void DoSomething<T>(this T item)
where T : IDisposable
{ /* whatever else */ }
}
如果我現在使用擴展方法
var instance = new MyClass();
instance.DoSomething();
將使用哪種方法? 或者編譯器會拋出錯誤?
注意:我不是說這是好設計,甚至我說我需要這樣做。 但是“更具體”這個詞足以讓我思考這一點,現在我必須知道! :P
更新:我想我是不是真的在上面的例子中會發生什么 ,在為什么感興趣。 因為我做過類似的事情,所以我想到了
public static class CollectionExtensions
{
public static void DoSomething<T>(this T items) where T : IList { ... }
public static void DoSomething<T>(this T items) where T : IEnumerable { ... }
}
編譯器知道為new List<Something>().DoSomething()
選擇第一種方法,因為它與傳遞的類型“更接近”。 我當時感興趣的是“在這種情況下更接近的意思是什么?如果約束來自兩個不同的繼承鏈,編譯器將如何反應?為什么?”
它根本不會編譯並拋出編譯時錯誤,說兩個方法之間的調用是不明確的。
類型'MyExtensions'已經定義了一個名為'DoSomething'的成員,它具有相同的參數類型。
這就是編譯器給出這樣的錯誤的原因。 擴展方法只是語法糖,它們所做的就是為任何類型帶來流暢性和可讀性。
檢查此代碼..
var instance = new MyClass();
instance.DoSomething();
編譯器將此代碼替換為以下內容。
var instance = new MyClass();
MyExtensions.DoSomething(instance);
//Compiler gets confused. Which one to call IComparable or IDisposable
在你的情況下編譯器會混淆,因為方法調用有兩個匹配的簽名,它會給你所說的錯誤。
通用約束不被視為方法簽名的一部分。 編譯器將這兩種方法視為具有相同簽名的方法。 所以你會得到編譯錯誤,說已經定義了DoSomething
方法。
public static void DoSomething<T>(this T item)
where T : IComparable
{ /* whatever */ }
public static void DoSomething<T>(this T item)
where T : IDisposable
{ /* whatever else */ }
請考慮以下示例:
class MyClass {}
static class MyClassExtensions
{
public static void DoSomething<T>(this T item, List<string> someList)
{
Console.WriteLine("Method with List in signature is called.");
}
public static void DoSomething<T>(this T item, IEnumerable<string> someEnumerable)
{
Console.WriteLine("Method with IEnumerable in signature is called.");
}
}
在此示例中,使用以下內容進行測試時:
var myClass = new MyClass();
myClass.DoSomething(new List<string>());
調用擴展類中的第一個方法。 簡而言之,這意味着編譯器確定更接近傳遞的參數的簽名,並使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.