2009-11-18 115 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>()); 
相关问题