【问题标题】:How do I write a generic method that takes different types as parameters?如何编写一个将不同类型作为参数的泛型方法?
【发布时间】:2009-11-18 05:52:25
【问题描述】:

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

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

【问题讨论】:

    标签: c# generics parameters extension-methods


    【解决方案1】:

    这个方法会给你你想要的:

    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 的类型限制为 Animal 类型层次结构中的任何内容;扩展方法可以在任何你有一种类型派生自另一种类型的地方使用。
    3. 这并不是编译器无法推断类型的真正问题。即使您在各处显式传递了 A 和 B 的类型,您仍然会收到编译器错误。

    【讨论】:

    • 感谢您的代码,它运行良好!起初我认为这意味着 AddRange() 需要一个键值对,但我认为它可以根据参数区分差异。没错,这不是类型推断的问题,而是类型转换的问题。
    【解决方案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);    
    } }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        我会使用约束来限制类型。

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

        【讨论】:

          【解决方案5】:
          public static void AddRange<TA, TB>(this ICollection<TA> collection, 
                                              IEnumerable<TB> list) where TB : TA
          

          (包含克雷格·沃克的评论)

          【讨论】:

          • 如果没有方法末尾的“where TB: TA”子句,这将不起作用。
          猜你喜欢
          • 2021-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-23
          • 1970-01-01
          相关资源
          最近更新 更多