11

検討

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です。後者は前者の構文糖衣ではありませんか?

4

2 に答える 2

18

マークの答えは正しいですが、もう少し説明が必要です。

この問題は、メソッド グループの処理方法とラムダの処理方法の微妙な違いによるものです。

具体的には、微妙な違いは、戻り値の型が一致するかどうかではなく、引数が一致するかどうかのみに基づいて、メソッド グループがデリゲート型に変換可能であると見なされることです。ラムダは、引数と戻り値の型の両方をチェックします。

この奇妙な規則の理由は、デリゲートへのメソッド グループの変換が、本質的にオーバーロード解決の問題の解決策であるためです。D がデリゲート型double D(string s)で、M が文字列を受け取って文字列を返すメソッドを含むメソッド グループであるとします。M から D への変換の意味を解決するとき、あたかも M(string) と言ったかのようにオーバーロードの解決を行います。オーバーロードの解決では、文字列を受け取って文字列を返す M が選択されるため、後でエラーが発生する場合でも、M はそのデリゲート型に変換できます。「string s = M(null);」と言った場合、「通常の」オーバーロード解決が成功するのと同じように。-- オーバーロードの解決は成功しますが、後で変換が失敗します。

このルールは微妙で、少し奇妙です。ここでの結論は、メソッド グループが、デリゲートを取る Sum のすべてのバージョンの2 番目の引数であるすべての異なるデリゲート タイプに変換可能であることです。最適な変換が見つからないため、メソッド グループのオーバーロードの解決はあいまいです。Sum

メソッド グループの変換規則は妥当ですが、C# では少し奇妙です。私は、それらがより「直感的に正しい」ラムダ変換と一致していないことに少し腹を立てています。

于 2011-10-13T02:35:03.590 に答える
8

s => GetValue(s)はラムダ式でGetValueあり、メソッド グループであり、まったく別のものです。どちらも のシンタックス シュガーと見なすことができますnew Func<string,double>(...)が、それらが相互に関連する唯一の方法は、ラムダ式に への呼び出しが含まれていることGetValue()です。デリゲートへの変換に関しては、メソッド グループには、戻り値の型に関してラムダ式とは異なる変換規則があります。Func<T> が Func<IEnumerable<T>> とあいまいな理由を参照してください。オーバーロードされたメソッドグループ引数はオーバーロードの解決を混乱させますか? .

于 2011-10-12T20:14:17.197 に答える