Как мне написать универсальный метод, который принимает различные типы в качестве параметров? - PullRequest
2 голосов
/ 18 ноября 2009

У меня есть следующий метод расширения, чтобы добавить элементы из одной коллекции в другую коллекцию:

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 ]

5 голосов
/ 18 ноября 2009

Этот метод даст вам то, что вы хотите:

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. Единственный способ, которым это может работать, - это использовать тип для B, производный от A. Например, Dog является подклассом Animal, поэтому AddRange будет работать. Это обеспечивается предложением «где B: A». Без этого вызов ICollection.Add () не будет выполнен из-за несовместимого типа для B, передаваемого в ICollection, ожидающего A.
  2. Нет большой необходимости ограничивать тип A чем-либо в иерархии типов Animal; метод расширения может использоваться везде, где у вас есть один тип, производный от другого.
  3. На самом деле проблема не в том, что компилятор не может выводить типы. Даже если вы явно передали типы для A и B везде, вы все равно получите ошибку компилятора.
2 голосов
/ 18 ноября 2009

Вы можете сделать это:

public static void AddRange<T,T2>(this ICollection<T> collection, IEnumerable<T2> list) where T2: T {
foreach (var item in list)  {                     
    collection.Add(item);    
} }
1 голос
/ 18 ноября 2009

дождитесь C # 4.0 или используйте метод расширения Linq Cast:

List<Animal> animals = new List<Animal>();
List<Dog> dogs = new List<Dog>();
animals.AddRange(dogs.Cast<Animal>());
0 голосов
/ 18 ноября 2009

Я бы использовал ограничение для ограничения типа.

    public static void AddRange<T, TK>(this ICollection<T> collection, IEnumerable<TK> list) where TK : T
    {
        foreach (var item in list)
        {
            collection.Add(item);
        }
    }
0 голосов
/ 18 ноября 2009
public static void AddRange<TA, TB>(this ICollection<TA> collection, 
                                    IEnumerable<TB> list) where TB : TA

(включенный комментарий Крейга Уокера)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...