Есть задача приведения типов.
class A{}
class A1:A{}
class A2:A1{}
class B<T> where T:A{}
class B1<T>:B<T> where T:A1{}
class B2:B1<A2>{}
B2-->B1<A1>
Возникает ошибка приведения типов. Как реализовать приведение типов?
Никак. Представьте, что в B1 у вас реализован вот так:
class B1<T> : B<T> where T : A1
{
public T Some;
}
И где-то есть код, который, встретив результат вашей конвертации B2-->B1<A1> в виде B1<A1> b1 делает:
b1.Some = new A1();
А ведь b1 - это объект типа B2, и b1.Some - это на самом деле поле типа A2.
Компилятор не может проанализировать реализацию какого-то стороннего, по отношению к коду B2-->B1<A1>, класса. Компилятор не может предугадать, что дальше с результатом конвертации произойдет. Так что он просто запрещает саму конвертацию.
При этом проблема возникает только из-за наличия какой-то внутренней реализации класса B1, невидимой для компилятора в момент прохода по коду конвертации. Если использовать вместо класса B1 интерфейс - то проблема легко решается добавлением модификаторов in / out.
Смотрите.
У нас известно, что B2 является (в смысле «is a», подтип) B1<A2>. Но B1<A2> не является B1<A1> несмотря на то, что A2 является A1.
Почему так? Давайте рассмотрим на конкретном примере. Допустим, у нас есть List<A2>, почему его нельзя закастить в List<A1>, хотя A2 можно закастить в A1? Потому что иначе было бы возможно вот что:
List<A2> good = new List<A2>();
List<A1> evil = (List<A1>)good;
evil.Add(new A1()); // катастрофа!
A2 a2 = good[0]; // в списке оказался A1!
По этой причине компилятор запрещает преобразование из List<A2> в List<A1>. Ну и по той же причине — из B1<A2> в B1<A1>.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости