Как передать список классов в список интерфейсов?

У меня есть такая функция:

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. Если вы хотите добавить элементы в список, то, что вы просите, не является типичным и может не разрешаться в С# в результате.