Как передать список классов в список интерфейсов?
У меня есть такая функция:
DoSomething(List<IMyInterface>)
IMyInterface - это интерфейс, а MyClass - это класс, реализующий этот интерфейс
Класс MyClass: IMyInterface
Я вызываю DoSomething(List<MyClass>)
, и похоже, что он не работает.
Как передать список классов в список интерфейса класса в качестве параметра функции? Спасибо!
Ответы
Ответ 1
Если ваш код просто выполняет итерацию по последовательности внутри метода (не добавляя, не удаляя или не получая доступ по индексу), измените свой метод на один из следующих
DoSomething(IEnumerable<IMyInterface> sequence)
DoSomething<T>(IEnumerable<T> sequence) where T : IMyInterface
Интерфейс IEnumerable<>
является ковариантным (начиная с .NET 4) (первый вариант). Или вы можете использовать последнюю подпись, если используете С# 3.
В противном случае, если вам нужны индексированные операции, преобразуйте список перед его передачей. В вызове у вас может быть
// invocation using existing method signature
DoSomething(yourList.Cast<IMyInterface>().ToList());
// or updating method signature to make it generic
DoSomething<T>(IList<T> list) where T : IMyInterface
То, что последняя подпись позволит вам сделать, это также поддерживать добавление или удаление в список (видимый на call-сайте), а также позволит вам использовать список без его первого копирования.
Даже если все, что вы делаете, перебирает список в цикле, я бы одобрил метод acceping IEnumerable<>
.
Ответ 2
Это вообще небезопасно, потому что списки изменяемы. Предположим, вы передали кому-то ссылку на List<MyClass>
как List<IMyInterface>
, а затем:
void Foo(List<IMyInterface> list)
{
IMyInterface x = new MyOtherClassWhichAlsoImplementsIMyInterface();
list.Add(x);
}
Теперь ваш List<MyClass>
содержит экземпляр класса, который не является MyClass
. Это нарушит безопасность типов. (Как отмечалось в других ответах, вы можете избежать этой проблемы, передав только интерфейс IEnumerable<>
List, который обеспечивает доступ только для чтения и, следовательно, безопасен).
Подробнее см. Использование разницы в интерфейсах для общих коллекций в MSDN. См. Также хорошее резюме ковариации и контравариантности и различных функций С#, которые поддерживают его.
Ответ 3
Если вам нужно только пройти список, объявите метод с помощью IEnumerable. Если вы хотите добавить элементы в список, то, что вы просите, не является типичным и может не разрешаться в С# в результате.