私は次のコードを持っています:
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では、これが使用されています)。おそらく誰かが問題を明確にすることができます。ありがとう。
他の人たちは、あなたがcouldが意味する可能性がある無限の可能なデリゲートタイプがあることをすでに指摘しています。 Func
やPredicate
の代わりにデフォルトになるに値するほどAction
の特別な点は何ですか?また、ラムダの場合、式ツリー形式ではなくデリゲート形式を選択することが意図されていることが明らかなのはなぜですか?
しかし、Func
は特別であり、ラムダまたは匿名メソッドの推定型は何かのFuncであると言えます。まだあらゆる種類の問題があります。次の場合にどのタイプを推測しますか?
var x1 = (ref int y)=>123;
Refを取得するFunc<T>
タイプはありません。
var x2 = y=>123;
戻り値はわかりますが、仮パラメーターの型はわかりません。 (または、戻り値はint?long?short?byte?)
var x3 = (int y)=>null;
戻り値の型はわかりませんが、無効にすることはできません。戻り値の型は、任意の参照型またはNULL値を許可する値型です。
var x4 = (int y)=>{ throw new Exception(); }
繰り返しますが、戻り値の型はわかりませんが、今回はvoidにすることができます。
var x5 = (int y)=> q += y;
それは、voidを返すステートメントlambdaか、qに割り当てられた値を返す何かを意図したものですか?両方とも合法です。どちらを選ぶべきですか?
さて、あなたは、それらの機能のいずれもサポートしていないと言うかもしれません。タイプをうまく処理できる「通常の」ケースをサポートしてください。それは役に立ちません。どうすれば私の生活が楽になりますか?機能が時々動作し、時々失敗する場合、それらの失敗状況のすべてにdetectにコードを記述し、それぞれの意味のあるエラーメッセージ。それでも、すべての動作を指定し、文書化し、テストを作成する必要があります。これは、非常に高価な機能であり、ユーザーのキーストロークを半ダース節約できます。半分の時間で機能せず、機能する場合にほとんどメリットをもたらさない機能のテストケースを書くのに多くの時間を費やすよりも、言語に価値を付加するより良い方法があります。
実際に役立つ状況は次のとおりです。
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型が何であるかを決定します。
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
コンパイラはどちらを推測すべきですか?どちらかを選択する正当な理由はありません。また、Predicate<T>
はFunc<T, bool>
と機能的に同等ですが、.NETタイプシステムのレベルでは依然として異なるタイプです。したがって、コンパイラはデリゲート型を明確に解決できず、型推論に失敗する必要があります。
Eric Lippertには古い post があり、彼の言うところ
実際、C#2.0仕様ではこれを呼び出しています。メソッドグループ式と匿名メソッド式は、C#2.0では型のない式であり、ラムダ式はC#3.0ではそれらを結合します。したがって、暗黙の宣言の右側に「裸」に見えることは違法です。
異なるデリゲートは異なるタイプと見なされます。たとえば、Action
はMethodInvoker
とは異なり、Action
のインスタンスをMethodInvoker
型の変数に割り当てることはできません。
したがって、() => {}
のような匿名デリゲート(またはラムダ)が与えられた場合、それはAction
またはMethodInvoker
ですか?コンパイラーは判断できません。
同様に、string
引数を取り、bool
を返すデリゲート型を宣言した場合、コンパイラは、デリゲート型の代わりにFunc<string, bool>
が本当に必要であることをどのように知るのでしょうか。デリゲートタイプを推測することはできません。
次のポイントは、暗黙的に型指定されたローカル変数に関するMSDNからのものです。
匿名メソッドに関する次のことを考慮してください。
無名メソッドは実際には異なるメソッドシグネチャを持っている可能性があるため、コンパイラは割り当てるのに最も適切なタイプが何であるかを適切に推測することはできません。
私の投稿は実際の質問には答えませんが、以下の根本的な質問には答えます。
「Func<string, string, int, CustomInputType, bool, ReturnType>
のような不気味なタイプを入力しなくて済むようにするにはどうすればよいですか?」 [1]
私は怠け者/ハッカーのプログラマーなので、Func<dynamic, object>
を使用して実験しました。これは、単一の入力パラメーターを受け取り、オブジェクトを返します。
複数の引数の場合、次のように使用できます。
dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));
ヒント:オブジェクトを返す必要がない場合は、Action<dynamic>
を使用できます。
ええ、おそらくあなたのプログラミングの原則に反することを知っていますが、これは私にとって理にかなっており、おそらくいくつかのPythonコーダー。
私はデリゲートの初心者です...私が学んだことを共有したかっただけです。
[1] これは、パラメーターとして事前定義されたFunc
を必要とするメソッドを呼び出さないことを前提としています。その場合、そのひどい文字列を入力する必要があります:/
それはどうですか?
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);