Быть скучным человеком, который дает ответ «потому что это то, что говорит спецификация» (TL; DR в конце с моими мыслями) ...
По сути, это потому, что преобразования групп методов (например, назначение)метод делегата) и преобразования анонимных функций (например, назначение лямбды делегату) следуют другим правилам, и только первые получают преимущество от дисперсии.
(Обратите внимание, что Method Group
означает группу из 1 илибольше перегрузок одного и того же метода - поэтому ваши отдельные методы по-прежнему считаются отдельными группами методов)
В разделе 6.5 спецификации языка C # говорится о преобразованиях анонимных функций:
Выражение анонимного метода или лямбда-выражения классифицируется как анонимная функция (§7.15).Выражение не имеет типа, но может быть неявно преобразовано в совместимый тип делегата или тип дерева выражений.В частности, анонимная функция F совместима с типом делегата D при условии:
- ...
- Если F имеет список параметров с явным типом ввода, каждый параметр в D имеет тот же типи модификаторы как соответствующий параметр в F.
В разделе 6.6, однако, говорится о преобразованиях группы методов:
Неявное преобразование (§6.1) существует из методагруппа (§7.1) для совместимого типа делегата.Учитывая тип делегата D и выражение E, которое классифицируется как группа методов, существует неявное преобразование из E в D, если E содержит хотя бы один метод, который применим в своей нормальной форме (§7.5.3.1) к построенному списку аргументовс использованием типов параметров и модификаторов D, как описано ниже.
Применение во время компиляции преобразования из группы методов E в тип делегата D описано ниже.Обратите внимание, что существование неявного преобразования из E в D не гарантирует, что применение преобразования во время компиляции будет выполнено без ошибок.
- Выбран один метод M, соответствующий вызову метода (§7.6.5.1) формы E (A) со следующими модификациями:
- Список аргументов A представляет собой список выражений, каждое из которых классифицируется как переменная, с типом и модификатором (ref или out)соответствующего параметра в списке формальных параметров D.
- Рассмотренными методами-кандидатами являются только те методы, которые применимы в их обычной форме (§7.5.3.1), а не те, которые применимы только в их расширенной форме.
Таким образом, группа методов -> преобразование делегата использует более или менее те же правила, как если бы вы пытались вызвать метод с соответствующими типами параметров.Мы направлены в Раздел 7.6.5.1, который направляет нас в Раздел 7.5.3.1.Это становится сложным, поэтому я не собираюсь вставлять его дословно здесь.
Интересно, что я не смог найти раздел о ковариации делегатов, только ковариации интерфейса (хотя в разделе 6.6 сказано упомянуть об этом в примере).
TL; DR, когда вы пишете:
SampleDelegate test = SomeMethodGroup;
, компилятор проходит весь алгоритм, чтобы выбрать подходящий член группы методов, который совместим с типом делегата., следуя тем же правилам, что и разрешение перегрузки, если вы вызывали метод.
Когда вы пишете:
SampleDelegate test = (First first) => new Second();
, компилятор следует гораздо более простому правилу: «соответствует ли сигнатура лямбдыподпись делегата ".
Полагаю, это имеет смысл.Большую часть времени вы будете писать:
SampleDelegate test = first => new Second();
, и компилятор должен выяснить типы параметров из сигнатуры делегата.Если вы добавляете явные типы самостоятельно, это не меняет полностью используемый алгоритм: компилятор использует тот же алгоритм, но если типы сталкиваются с конфликтами с вашими явными типами, вы получаете ошибку.
Обратите внимание, что почти все время это не имеет значения .Редко ставить типы в параметры лямбды, поэтому вы обычно пишете так:
SampleDelegate test = x => new Second();
Компилятор делает вывод, что x
на самом деле Second
, и это нормально: если вы написалилямбда, которая может работать, если x
является First
, она также должна работать, если x
является Second
(несмотря на LSP).Обратите внимание, что вам разрешено возвращать Second
, хотя SampleDelegate
возвращает первое: компилятор не возражает.