The_Unknown_Member Ответов: 1

C# как работает явное приведение с дженериками во время компиляции?


Привет. Я экспериментировал с концепцией ковариации в универсальных интерфейсах и наткнулся на то, о чем хочу вас спросить
Я знаю, что этот код не будет работать:
List<Base> randomList = new List<Derived>();

Это не работает, потому что они отличаются своими общими параметрами.

Этот код также не будет работать:
IList<Derived> derived = new List<Derived>();
            IList <Base> basee = derived;


Но если я сделаю гипс:
IList <Base> basee = (IList<Base>)derived;

Компилятор не будет жаловаться. Я знаю, что он потерпит неудачу во время выполнения, потому что списки не поддерживают ковариацию, но здесь я спрашиваю о том, почему это приведение разрешено.
На что смотрит компилятор, решая, разрешено ли приведение или нет?

Что я уже пробовал:

Попытался найти ответ в Microsoft Docs, но они не говорили о явном кастинге в терминах дженериков.

1 Ответов

Рейтинг:
1

Maciej Los

Цитата:
Это не работает, потому что они отличаются своими общими параметрами.

Я не понимаю вышеизложенного утверждения. Тем не менее...

Короче говоря: вы не можете создать список базового класса, передавая новый список производного класса! Вы должны явным образом преобразовать производный класс в базовый класс:
List<MyDerived> derivedList = new List<MyDerived>();
derivedList.Add(new MyDerived("a"));
derivedList.Add(new MyDerived("b"));
List<MyBase> baseList = derivedList.Cast<MyBase>().ToList();
//you can add MyDerived class without casting, because of its base class ;)
baseList.Add(new MyDerived("c"));


Пожалуйста, обратитесь к ним для получения более подробной информации:
база данных (Справочник по C#) | Microsoft Docs[^]
Приведение и преобразование типов (руководство по программированию на C#) | Microsoft Docs[^]
Как безопасно выполнять приведение с помощью операторов as и is (руководство по программированию на C#) | Microsoft Docs[^]


The_Unknown_Member

Я имел в виду, что это не сработает, потому что список T не поддерживает ковариацию (классы не могут поддерживать ковариацию + в этом случае это нарушит безопасность типов). Речь идет в основном о второй части

То IList&ЛТ;производные&ГТ; производные = новый список<производные&ГТ;();
IList <base /> basee = производный;


В частности эта строка:
IList <base /> basee = производный;

Здесь мне разрешено привести производный к IList<base /> (Конечно, он потерпит неудачу во время выполнения, но здесь я говорю о времени компиляции). Как компилятор определил это
производный список можно привести к IList? Заботится ли он об общих параметрах? Или он просто заботится о дереве наследования List<t> Так что в этом случае IList<t> реализуется List<t> Следовательно, компилятор позволяет мне привести мой список к IList, не заботясь о дженериках. Так ли это на самом деле?

Maciej Los

IList это не класс. Это интерфейс. Это имеет значение!

The_Unknown_Member

@Maciej Los Да, я это знаю.