IList <IWhothing> как параметр метода

2

У меня есть два IList<ICat>, и я пытаюсь создать метод, который принимает IList<ICat> и выполняет некоторую работу. У меня возникают проблемы с попыткой передать либо IList<PussyCat>, либо IList<OtherCat>, как PussyCat, так и OtherCat реализовать ICat.

Я пробовал:

List<PussyCat> cats = ...
DoWork((IList<ICat>)cats);

и просто

DoWork(cats);

Но не скомпилируйте. Любые идеи?

  • 0
    покажите подпись вашего метода Dowork () ...
Теги:
generics
interface

4 ответа

7
Лучший ответ

Генерации С# являются инвариантными. Это означает, что List<string> не является List<object>.

С# 4.0 вводит безопасную ковариацию/контравариантность, но вы не сможете пройти List<string> как List<object>. Причина в том, что:

List<string> x = new List<string>();
List<object> o = x; // assume this statement is valid
o.Add(5); // Adding an integer to a list of strings. Unsafe. Will throw.

Массивы, с другой стороны, являются ковариантными. Вы можете передать string[] методу, который ожидает object[].

  • 0
    Спасибо. Я читал о совместной и противоречивой дисперсии, но я думаю, что более тщательное чтение с моей стороны необходимо. Я нахожу, что мне «нужно» C # 4.0 все больше и больше.
  • 3
    Обратите внимание , что если DoWork только foreach ИНГ коллекции и ничего не меняется, вы можете объявить параметр как IEnumerable<ICat> и вызовите его DoWork(cats.Cast<ICat>()) .
5

Существует две альтернативы:

  • Сделайте свой метод следующим:

    public void DoWork< T > (IList< T > cats_) where T : ICat
    {
        //Do work;
    }
    
  • Другая возможность - иметь такой метод, как

    public void DoWork(IList< ICat > cats_) 
    {
        //Do work;
    }
    

    и назовите его следующим образом:

    {
        //....Assuming: IList<PussyCat> iListOfPussyCats
        List<PussyCat> pussyCats = new List<PussyCats>(iListOfPussyCats);
        DoWork(pussyCats.ConvertAll<ICat>( c => c as ICat);
    }
    
  • 0
    +1 для универсальной версии (обратите внимание, что это ни в коем случае не является неэффективным: во время выполнения один универсальный экземпляр с T = ICat будет использоваться для всех возможных случаев)
1

Если метод действительно не требует прямой индексации (IList<T>) и не требует добавления/удаления элементов (ICollection<T>), то передайте IEnumerable<T>. Методы расширения Cast<T>() позволяют передавать любые IList из [insert ICat -derived type] в качестве IEnumerable<ICat>.

0

До появления С# 4.0, который поддерживает поддержку co и contra variance, вы можете уйти от чего-то вроде этого:

public void DoWork(IEnumerable<ICat> cats)
{
  //do something 
}
 List<PussyCat> pussyCats = new List<PussyCat>;
 List<OtherCat> otherCats = new List<OtherCat>;
 DoWork(pussyCats.OfType<ICat>);
 DoWork(otherCats.OfType<ICat>);
  • 1
    Как я уже сказал, в C # 4.0 для этой конкретной ситуации ничего не изменится, и OfType возвращает IEnumerable не IList .
  • 0
    К сожалению. Вы правы. Я исправил код

Ещё вопросы

Сообщество Overcoder
Наверх
Меню