6

型推論について少し検索しましたが、特定の問題に解決策を適用できないようです。

関数の構築と受け渡しで多くの作業を行っています。これは、int型を推測できるように思えます。私が考えることができる唯一のことは、ラムダの戻り値の型が型推論アルゴリズムによってチェックされていないということです。問題をより明確に示すために、不必要なロジックを削除しました。

Func<T> Test<T>(Func<Func<T>> func)
{
    return func();
}

これはコンパイルされます:

Func<int> x = Test<int>(() =>
    {
        int i = 0;
        return () => i;
    });

しかし、これにより、「メソッドの型引数は使用法から推測できません。型引数を明示的に指定してみてください」というエラーが発生します。

Func<int> x = Test(() =>
    {
        int i = 0;
        return () => i;
    });

このように動作する理由と回避策を知りたいだけだと思います。

4

1 に答える 1

8

質問に対する正しい答えは、E.Lippert のSO なぜ匿名メソッドを var に割り当てることができないのですか?によって与えられていると思います。

しかし、あなたの例で少し遊んでみましょう:

Func<Func<int>> f = () =>
{
    int i = 0;
    return () => i;
};

Func<int> x = Test(f); //it compiles OK

ここで型推論に問題はありませんFunc<T> Test<T>(Func<Func<T>> func)。問題は、型を推測できない匿名のラムダ式を使用していることに隠されています。これを試して:

var f = () =>
{
    int i = 0;
    return () => i;
};

Compiler Error CS0815が表示され、

暗黙的に型指定されたローカル変数にラムダ式を割り当てることはできません

説明は次のとおりです。

暗黙的に型指定された変数の初期化子として使用される式には、型が必要です。無名関数式、メソッド グループ式、および null リテラル式には型がないため、適切な初期化子ではありません。暗黙的に型指定された変数は、宣言で null 値を使用して初期化することはできませんが、後で null の値を割り当てることはできます。

それでは、別のことを試してみましょう。

var x = Test(() =>
{
    Func<int> f = () => 0;
    return f;
});

同様にコンパイルします。したがって、元の例の問題は、実際には次の行にありました。

return () => i; 

さらに先に進むことができ、エリック・リッパートが彼の答えで言っていることによると、これをラップする別の関数を提供します:

static Func<T> GetFunc<T>(Func<T> f) { return f; }

これで、コードを次のように書き直すことができます。

var x = Test(() =>
{
    int i = 0;
    return GetFunc(() => i);
});

そして、それも同様に機能します。

ただし、私が理解している限り、これはすべてオーバーヘッドであり、明示的な型を指定する必要があります。これらの回避策は適切ですが、ラムダが必要な場合は、匿名型のオブジェクトを返します。

于 2013-03-29T03:06:31.340 に答える