如何编写将不同类型作为参数的泛型方法?

时间:2009-11-18 05:52:26

标签: c# generics parameters extension-methods

我有以下扩展方法将一个集合中的元素添加到另一个集合中:

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

如果IEnumerable列表与我试图将其添加到的ICollection的类型相同,这可以正常工作。但是,如果我有这样的事情:

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的类型是T类型的子类(或实现接口),如何修改我的扩展方法以便能够执行此类操作?

5 个答案:

答案 0 :(得分: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的不兼容类型被传递到期望A的ICollection。
  2. 在动物类型层次结构中,没有太多需要将A的类型限制为任何内容;扩展方法可用于任何一种类型派生自另一种类型的地方。
  3. 这不是编译器无法推断类型的问题。即使你在任何地方明确地传递了A和B的类型,你仍然会遇到编译器错误。

答案 1 :(得分: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);    
} }

答案 2 :(得分:1)

等待C# 4.0或使用Linq扩展方法Cast

List<Animal> animals = new List<Animal>();
List<Dog> dogs = new List<Dog>();
animals.AddRange(dogs.Cast<Animal>());

答案 3 :(得分:0)

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

(并入Craig Walker的评论)

答案 4 :(得分: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);
        }
    }