Похоже, что компилятор делает это из-за некоторых проблем с верификатором.
IL, который вы хотите, чтобы компилятор генерировал, не подлежит проверке, и поэтому компилятор C # не может его сгенерировать (весь код C # за пределами "небезопасных" контекстов должен проверяться).
Правила «проверки совместимости типов» приведены в Разделе 1.8.1.2.3, Часть III спецификации Ecma.
Они говорят, что тип 'S' совместим по верификации с типом 'T' или (S: = T), используя следующие правила:
- [: = является рефлексивным] Для всех типов проверки S, S: = S
- [: = является транзитивным] Для всех типов проверки S, T и U, если S: = T и T: = U, то S: = U.
- S: = T, если S - это базовый класс T или интерфейс, реализованный с помощью T, а T не является типом значения.
- object: = T, если T является типом интерфейса.
- S: = T, если S и T оба являются интерфейсами, а реализация T требует реализации
из S
- S: = ноль, если S - тип объекта или интерфейс
- S []: = T [], если S: = T и массивы либо оба вектора (основаны на нуле, ранг один), либо ни
является вектором, и оба имеют одинаковый ранг. (Это правило касается ковариации массива.)
- Если S и T являются указателями метода, то S: = T, если подписи (возвращаемые типы, типы параметров и
Соглашение о вызове) одинаковы.
Из этих правил единственное, что может быть применимо в этом случае, это # 3.
Однако # 3 не применяется к вашему коду, потому что «U» не является базовым классом «T» и не является базовым интерфейсом «T», поэтому проверка «или» возвращает false.
Это означает, что необходимо выполнить НЕКОТОРЫЕ инструкции, чтобы преобразовать коробочный T в U таким образом, чтобы он проходил через верификатор.
Я бы согласился с вами, что правила проверки должны быть изменены, чтобы генерируемый вами код действительно проверялся.
Технически, однако, компилятор делает «правильную» вещь, основываясь на спецификации ECMA.
Вам следует сообщить об ошибке кому-нибудь в Microsoft.