Ответ (что нет различий с типами значений) является правильным.Ковариация и контравариантность причины не работают, когда один из аргументов переменного типа является типом значения, заключается в следующем.Предположим, это сработало и покажет, как все идет ужасно неправильно:
Func<int> f1 = ()=>123;
Func<object> f2 = f1; // Suppose this were legal.
object ob = f2();
ОК, что происходит?f2 является идентичным ссылке f1.Поэтому, что бы ни делала f1, делает f2.Что делает f1?Он помещает 32-разрядное целое число в стек.Что делает задание?Он берет все, что находится в стеке, и сохраняет его в переменной «ob».
Где была инструкция по боксу? Не было ни одного!Мы просто сохранили 32-разрядное целое число в хранилище, которое ожидало не целое число, а 64-разрядный указатель на местоположение кучи, содержащее целое в штучной упаковке.Таким образом, вы просто сместили стек и испортили содержимое переменной с неверной ссылкой.Вскоре процесс затихнет.
Так куда же должна идти инструкция по боксу?Компилятор должен где-то сгенерировать инструкцию по боксу.Он не может идти после вызова f2, потому что компилятор считает, что f2 возвращает объект, который уже был упакован.Он не может перейти к вызову f1, потому что f1 возвращает int, а не упакованный int.Он не может идти между вызовом f2 и вызовом f1 , потому что они один и тот же делегат;между 1011 * нет.
Единственное, что мы могли бы здесь сделать, это заставить вторую строку на самом деле означать:
Func<object> f2 = ()=>(object)f1();
и теперь у нас больше нет ссылочной тождественности между f1 и f2, поэтому чтоэто точка отклонения ?Весь смысл наличия ковариантных эталонных преобразований состоит в том, чтобы сохранить эталонную идентификацию .
Независимо от того, как вы нарезаете его, все идет ужасно неправильно, и нет способа исправитьЭто.Поэтому лучшее, что нужно сделать, - это сделать функцию незаконной в первую очередь;не допускается отклонение в универсальных типах делегатов, где тип значения может варьироваться.
ОБНОВЛЕНИЕ: в моем ответе я должен был отметить, что в VB вы можете преобразоватьвозвращающий int делегат возвращающему объект делегату.VB просто создает второй делегат, который переносит вызов к первому делегату и упаковывает результат.VB решает отказаться от ограничения на то, что ссылочное преобразование сохраняет идентичность объекта.
Это иллюстрирует интересную разницу в философии дизайна C # и VB.В C # команда разработчиков всегда думает: «Как компилятор может найти ошибку в программе пользователя и довести ее до сведения?»и команда VB думает: «Как мы можем выяснить, что пользователь, вероятно, имел в виду, и просто сделать это от его имени?»Короче говоря, философия C # - «если ты что-то видишь, скажи что-нибудь», а философия VB - «делай, что я имею в виду, а не то, что я говорю».Оба - совершенно разумные философии;Интересно видеть, как два языка, которые имеют почти идентичные наборы функций, отличаются этими маленькими деталями из-за принципов проектирования.