Вывод метода не работает с группой методов

считают

void Main()
{
    var list = new[] {"1", "2", "3"};
    list.Sum(GetValue); //error CS0121
    list.Sum(s => GetValue(s)); //works !
}

double GetValue(string s)
{
    double val;
    double.TryParse(s, out val);
    return val;
}

описание ошибки CS0121 -

вызов неоднозначен между следующих методов или свойств: 'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal>)' и 'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal?>)'

чего я не понимаю, так это того, что делает информация s => GetValue(s) дайте компилятору, что просто GetValue не-не является ли последний синтаксический сахар для первого ?

2 ответов


ответ Марка правильный, но может использовать немного больше объяснений.

проблема действительно связана с тонкой разницей между тем, как обрабатываются группы методов и как обрабатываются лямбды.

в частности, тонкая разница заключается в том, что группа методов считается конвертируемой в тип делегата исключительно на основе того, является ли аргументы матч, а не Также на основе ли тип возвращаемого матчи. Lambdas проверяет как аргументы, так и возвращаемый тип.

причина этого нечетного правила заключается в том, что преобразования группы методов в делегаты по существу являются решением перегрузка разрешение проблема. Предположим, что D-тип делегата double D(string s) и M-группа методов, содержащая метод, который принимает строку и возвращает строку. При разрешении значения преобразования из M В D мы делаем разрешение перегрузки, как если бы вы сказали M(строка). Разрешение перегрузки выбрать M, который принимает строку и возвращает строку, и поэтому M преобразуется в этот тип делегата даже если преобразование приведет к ошибке позже. Точно так же, как" регулярное "разрешение перегрузки будет успешным, если вы скажете" string s = M(null); " -- разрешение перегрузки успешно, даже если это вызывает сбой преобразования позже.

это правило тонкое и немного странное. В результате здесь ваша группа методов конвертируется в все разные делегат типы это второй аргумент каждая версия Sum, которая принимает делегат. Поскольку лучшее преобразование не найдено, разрешение перегрузки для группы методов Sum неоднозначно.

правила преобразования групп методов правдоподобны, но немного нечетны в C#. Я несколько раздосадован тем, что они не согласуются с более "интуитивно правильными" лямбда-преобразованиями.


s => GetValue(s) является лямбда-выражением и GetValue - это группа методов, которая является совершенно другой вещью. Они оба могут считаться синтаксическим сахаром для new Func<string,double>(...) но единственный способ, которым они связаны друг с другом заключается в том, что лямбда-выражение содержит вызов GetValue(). Когда дело доходит до преобразования в делегат, группы методов имеют другие правила преобразования, чем лямбда-выражения в отношении возвращаемых типов. См.почему кнопку Func и неоднозначное с func>? и перегруженный метод-групповой аргумент путает разрешение перегрузки?.