150

次のコードがあります。

Func<string, bool> comparer = delegate(string value) {
    return value != "0";
};

ただし、以下はコンパイルされません。

var comparer = delegate(string value) {
    return value != "0";
};

コンパイラがそれが であると判断できないのはなぜFunc<string, bool>ですか? 1 つの文字列パラメーターを取り、ブール値を返します。代わりに、次のエラーが表示されます。

匿名メソッドを暗黙的に型指定されたローカル変数に割り当てることはできません。

私は1つの推測を持っています.varバージョンがコンパイルされた場合、次のようにすると一貫性が失われます:

var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
    return false;
};

Func<> は最大4つの引数しか許可しないため、上記は意味がありません(.NET 3.5では、これを使用しています)。おそらく、誰かが問題を明確にすることができます。ありがとう。

4

7 に答える 7

162

他の人は、あなたが意味した可能性のあるデリゲート型が無限にあることをすでに指摘しています。またはその他の可能性Funcではなく、デフォルトに値するほど特別なものは何ですか? また、ラムダの場合、意図が式ツリー形式ではなくデリゲート形式を選択することであることが明らかなのはなぜでしょうか?PredicateAction

しかし、それFuncは特別なことであり、ラムダまたは匿名メソッドの推論された型は何かの Func であると言えます。私たちはまだあらゆる種類の問題を抱えているでしょう。次の場合、どのタイプを推測しますか?

var x1 = (ref int y)=>123;

Func<T>ref何かを取るタイプはありません。

var x2 = y=>123;

戻り値はわかっていますが、仮パラメータの型はわかりません。(または、戻り値は int ですか? long ですか? short ですか? byte ですか?)

var x3 = (int y)=>null;

戻り値の型はわかりませんが、void にすることはできません。戻り値の型は、任意の参照型または null 許容値型にすることができます。

var x4 = (int y)=>{ throw new Exception(); }

繰り返しますが、戻り値の型はわかりません。今回はvoidになる可能性があります。

var x5 = (int y)=> q += y;

これは、void を返すステートメント ラムダまたは q に割り当てられた値を返すものを意図したものですか? どちらも合法です。私たちはどれを選ぶべきですか?

さて、これらの機能はどれもサポートしていないと言うかもしれません。タイプを解決できる「通常の」ケースをサポートするだけです。それは役に立ちません。それは私の人生をどのように楽にしてくれますか? 機能が時々機能し、時々失敗する場合でも、それらすべての失敗状況を検出し、それぞれに意味のあるエラー メッセージを表示するコードを作成する必要があります。すべての動作を指定し、文書化し、テストを作成する必要があります。これは非常に高価な機能であり、ユーザーはおそらく半ダースのキーストロークを節約できます。言語に価値を付加するには、機能の半分の時間しか機能せず、機能する場合にほとんどメリットがない機能のテスト ケースを書くのに多くの時間を費やすよりも優れた方法があります。

実際に役立つ状況は次のとおりです。

var xAnon = (int y)=>new { Y = y };

そのことには「話せる」タイプがないからです。しかし、私たちは常にこの問題を抱えており、メソッドの型推論を使用して型を推測しています。

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });

これで、メソッド型の推論により、func 型が何であるかがわかります。

于 2011-02-11T06:58:17.280 に答える
32

確かに知っているのは Eric Lippert だけですが、デリゲート型のシグネチャが型を一意に決定しないためだと思います。

あなたの例を考えてみましょう:

var comparer = delegate(string value) { return value != "0"; };

varがどうあるべきかについての 2 つの可能な推論を以下に示します。

Predicate<string> comparer  = delegate(string value) { return value != "0"; };  // okay
Func<string, bool> comparer = delegate(string value) { return value != "0"; };  // also okay

コンパイラはどちらを推測する必要がありますか? どちらか一方を選択する正当な理由はありません。aPredicate<T>は機能的には a と同等Func<T, bool>ですが、.NET 型システムのレベルでは依然として異なる型です。したがって、コンパイラはデリゲート型を明確に解決できず、型の推論に失敗する必要があります。

于 2011-02-11T04:35:03.103 に答える
6

Eric Lippert には、それについての古い投稿があります。

実際、C# 2.0 仕様はこれを要求しています。メソッド グループ式と匿名メソッド式は、C# 2.0 では型のない式であり、C# 3.0 ではラムダ式が結合されます。したがって、それらが暗黙の宣言の右側に「裸」で表示されることは違法です。

于 2011-02-11T04:40:24.873 に答える
5

異なるデリゲートは、異なるタイプと見なされます。たとえば、Actionは とは異なりMethodInvoker、 のインスタンスActionは 型の変数に代入できませんMethodInvoker

したがって、 のような匿名デリゲート (またはラムダ) が与えられた() => {}場合、ActionそれはMethodInvokerですか? コンパイラはわかりません。

同様に、string引数を取り、 を返すデリゲート型を宣言した場合、コンパイラは、デリゲート型の代わりにbool本当に が必要であることをどのように知るのでしょうか? Func<string, bool>デリゲート型を推測できません。

于 2011-02-11T04:34:44.777 に答える
2

次のポイントは、暗黙的に型指定されたローカル変数に関する MSDN からのものです。

  1. var は、ローカル変数が同じステートメントで宣言および初期化されている場合にのみ使用できます。変数を null に初期化することも、メソッド グループまたは無名関数に初期化することもできません。
  2. var キーワードは、初期化ステートメントの右側の式から変数の型を推測するようコンパイラーに指示します。
  3. var キーワードは「バリアント」を意味するものではなく、変数が緩く型付けされている、または遅延バインドされていることを示しているわけではないことを理解することが重要です。これは、コンパイラが最も適切な型を決定して割り当てることを意味します。

MSDN リファレンス: 暗黙的に型指定されたローカル変数

匿名メソッドに関して次の点を考慮してください。

  1. 匿名メソッドを使用すると、パラメーター リストを省略できます。

MSDN リファレンス: 匿名メソッド

匿名メソッドは実際には異なるメソッド シグネチャを持っている可能性があるため、コンパイラは割り当てるのに最も適切な型を適切に推測できないのではないかと思います。

于 2011-02-11T04:55:54.233 に答える
0

それはどうですか?

var item = new
    {
        toolisn = 100,
        LangId = "ENG",
        toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId)
        {
              var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html";
              return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : "";
        }
};

string result = item.toolPath(item.toolisn, item.LangId);
于 2013-12-19T08:07:55.743 に答える