Марк ответит правильно, но может использовать немного больше объяснений.
Проблема действительно заключается в тонкой разнице между тем, как обрабатываются группы методов, и тем, как обрабатываются лямбды.
В частности, тонкое различие заключается в том, что группа методов считается конвертируемой в тип делегата исключительно на основе соответствия аргументов , а не на основании того, является ли тип возвращаемого значения соответствует. Лямбда проверяет как аргументы, так и тип возвращаемого значения.
Причиной этого странного правила является то, что преобразование группы методов в делегаты по сути является решением проблемы разрешение перегрузки . Предположим, что D - это тип делегата double D(string s)
, а M - группа методов, содержащая метод, который принимает строку и возвращает строку. При определении значения преобразования из M в D мы разрешаем перегрузку, как если бы вы сказали M (строка). Разрешение перегрузки выберет M, которое принимает строку и возвращает строку, и поэтому M преобразуется в этот тип делегата , даже если преобразование приведет к ошибке позже . Точно так же, как «обычное» разрешение перегрузки будет успешным, если вы скажете «string s = M (null);» - разрешение перегрузки успешно выполняется, даже если это впоследствии приводит к сбою преобразования.
Это правило тонкое и немного странное. Результатом этого здесь является то, что ваша группа методов конвертируется в всех различных типов делегатов , которые являются вторыми аргументами каждой версии Sum, которая принимает делегата . Поскольку наилучшее преобразование не найдено, разрешение перегрузки для группы методов Sum
является неоднозначным.
Правила преобразования групп методов правдоподобны, но немного странны в C #. Меня несколько огорчает, что они не согласуются с более «интуитивно правильными» лямбда-преобразованиями.