2009-11-18 205 views
2

我有以下的擴展方法在一個集合中添加元素到另一個集合:如何編寫一個將不同類型作爲參數的泛型方法?

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> list) 
{ 
    foreach (var item in list) 
    {    
     collection.Add(item); 
    } 
} 

這工作得很好,如果IEnumerable的名單是相同類型的ICollection我試圖將它添加到。但是,如果我有這樣的事情:T形

var animals = new List<Animal>(); 
var dogs = new List<Dog>(); // dog is a subclass of animal 
animals.AddRange(dogs); // this line has a compiler error, it can't infer the type 

如何修改我的擴展方法,以便能夠做這樣的事情,如果IEnumerable的類型是子類(或實現接口)類型?

回答

5

這種方法會給你想要的東西:

public static void AddRange<A,B>(
    this ICollection<A> collection, 
    IEnumerable<B> list) 
    where B: A 
{ 
    foreach (var item in list) 
    { 
     collection.Add(item); 
    } 
} 

有兩點要注意:

  1. 這可以工作的唯一方法是如果您使用從A派生的B類型。例如,Dog是Animal的子類,所以AddRange將起作用。這由「where B:A」條款執行。如果沒有這個,ICollection.Add()調用將會失敗,因爲B被傳遞到ICollection中的類型不兼容,期望得到一個A.
  2. 沒有太多的需要將A的類型限制爲動物類型層次結構中的任何東西;擴展方法可以用於任何你有一個派生自另一個類型的地方。
  3. 這實際上不是一個編譯器無法推斷出類型的問題。即使你在任何地方明確地傳遞了A和B的類型,你仍然會得到一個編譯器錯誤。
+0

感謝您的代碼,它工作得很好!起初,我認爲這意味着AddRange()期待鍵值對,但我認爲它可以根據參數來區分差異。對,類型推斷不是問題,這是類型轉換的問題。 – 2009-11-18 21:16:59

0
public static void AddRange<TA, TB>(this ICollection<TA> collection, 
            IEnumerable<TB> list) where TB : TA 

(合併克雷格·沃克的評論)

+0

這不是沒有「TA其中TB」工作。 – 2009-11-18 06:28:50

+0

謝謝,克雷格。 (我知道我應該試過它) – peterchen 2009-11-18 07:42:39

+0

這就是「編輯」的全部內容:-) – 2009-11-18 15:34:36

2

你可以這樣做:

public static void AddRange<T,T2>(this ICollection<T> collection, IEnumerable<T2> list) where T2: T { 
foreach (var item in list) {      
    collection.Add(item);  
} } 
0

我會使用約束來限制類型。

public static void AddRange<T, TK>(this ICollection<T> collection, IEnumerable<TK> list) where TK : T 
    { 
     foreach (var item in list) 
     { 
      collection.Add(item); 
     } 
    } 
1

等待C# 4.0或使用LINQ的擴展方法Cast:在方法的結尾條款:

List<Animal> animals = new List<Animal>(); 
List<Dog> dogs = new List<Dog>(); 
animals.AddRange(dogs.Cast<Animal>()); 
相關問題