Невозможно преобразовать из списка в список

Я пытаюсь передать список DerivedClass функции, которая принимает список BaseClass , но я получаю ошибку:

 cannot convert from 'System.Collections.Generic.List' to 'System.Collections.Generic.List' 

Теперь я мог бы List свой List в List , но мне не комфортно это делать, если я не понимаю, почему компилятор этого не допускает.

Объяснения, которые я нашел, просто сказали, что это как-то нарушает безопасность типа, но я этого не вижу. Может кто-нибудь мне помочь?

Каков риск того, что компилятор разрешит преобразование из List в List ?


Вот мой SSCCE:

 class Program { public static void Main() { BaseClass bc = new DerivedClass(); // works fine List bcl = new List(); // this line has an error doSomething(new List()); // this line has an error } public void doSomething(List bc) { // do something with bc } } class BaseClass { } class DerivedClass : BaseClass { } 

Это потому, что List не in-variant , а не co-variant , поэтому вы должны перейти на IEnumerable который поддерживает co-variant , он должен работать:

 IEnumerable bcl = new List(); public void doSomething(IEnumerable bc) { // do something with bc } 

Информация о совместном варианте в родовом

Объяснения, которые я нашел, просто сказали, что это как-то нарушает безопасность типа, но я этого не вижу. Каков риск того, что компилятор разрешит преобразование из List в List ?

Этот вопрос задают почти каждый день.

List не может быть преобразован в List потому что вы можете помещать ящерицу в список животных . List > не может быть преобразован в List потому что в списке может быть тигр .

Поэтому List должен быть инвариантным в T.

Однако List может быть преобразован в IEnumerable (с C # 4.0), потому что нет метода в IEnumerable который добавляет ящерицу. IEnumerable ковариантно в T.

Поведение, которое вы описываете, называется ковариацией – если A является B , то List – это List .

Однако для изменяемых типов, таких как List , это принципиально небезопасно.

Если бы это было возможно, метод мог бы добавить new OtherDerivedClass() в список, который может фактически удерживать DerivedClass .

Ковариация безопасна для неизменяемых типов, хотя .Net поддерживает ее только в интерфейсах и делегатах.
Если вы измените параметр List на IEnumerable , это будет работать

Когда у вас есть class, полученный из базового classа, любые контейнеры этих classов автоматически не выводятся. Поэтому вы не можете просто передать List в List .

Используйте .Cast() чтобы создать новый список, в который каждый объект возвращается в базовый class:

 List list1 = new List(); List list2 = list1.Cast().ToList(); 

Обратите внимание, что это новый список, а не литая версия исходного списка, поэтому операции с этим новым списком не будут отображаться в исходном списке. Однако операции над содержащимися объектами будут отражаться.

Если бы вы могли написать

 List bcl = new List(); 

вы могли бы позвонить

 var instance = new AnotherClassInheritingFromBaseClass(); bc1.Add(instance); 

Добавление экземпляра, который не является DerivedClass в список.

Решением, которое я использовал, было создание classа расширения:

 public static class myExtensionClass { public void doSomething(List bc) where T: BaseClass { // do something with bc } } 

Он использует общий, но когда вы его вызываете, вам не нужно выделять class, поскольку вы уже «сказали» компилятору, что тип тот же, что и у расширенного classа.

Вы бы назвали это так:

 List lst = new List(); lst.doSomething(); 
  • Изменение значения элемента в списке структур
  • В чем разница между предварительным приращением и пост-приростом в цикле (для / while)?
  • LINQ to Entities поддерживает только листинг EDM примитивных или перечисляемых типов с интерфейсом IEntity
  • получение типа T из IEnumerable
  • Возможна ли пустая ссылка?
  • C ++, __try и try / catch / наконец
  • Метод подсчета вхождений в список
  • Что такое lambda-выражение в C ++ 11?
  • Хранение данных кредитной карты
  • Как печатать указатели функций с помощью cout?
  • Каково использование ключевого слова `default` в C #?
  • Interesting Posts

    Как преобразовать объект JSON в пользовательский объект C #?

    как установить символ с индексом в строке в c #?

    Можно ли преобразовать существующую установку Firefox в ESR без переустановки?

    GridView VS GridLayout в приложениях для Android

    Как перезапустить замороженный экран в Ubuntu без потери открытых окон?

    Как я могу запустить виртуальную машину без получения окна?

    Как создать ключ продукта для моего приложения C #?

    Гетерогенные контейнеры в C ++

    Как вы используете Intent.FLAG_ACTIVITY_CLEAR_TOP, чтобы очистить стек активности?

    C: унарный минус поведение оператора с неподписанными операндами

    Сообщения в Outlook только вычеркнуты и не удалены

    Тексты под иконками рабочего стола стали синими в Windows XP! Как я могу это исправить?

    Компиляция времени

    При выборе репозитория Android SDK Manager дает ошибку «Ошибка при получении URL https://dl-ssl.google.com/android/repository/repository.xml»

    Индивидуальный и не непрерывный выбор ячейки JTable

    Давайте будем гением компьютера.