web-dev-qa-db-ja.com

なぜc#はインライン匿名ラムダまたはデリゲートを使用できないのですか?

質問のタイトルを適切に表現したいと思います。

C#では、ラムダ(デリゲートとして)または古いデリゲート構文を使用してこれを行うことができます:

Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());

Func<string> fnHello2 = delegate()
{
    return "hello 2";
};
Console.WriteLine(fnHello2());

では、なぜラムダまたはデリゲート本体を「インライン化」して、名前付き変数にキャプチャする(匿名にする)のを避けることができないのでしょうか。

// Inline anonymous lambda not allowed
Console.WriteLine(
    (() => "hello inline lambda")()
);

// Inline anonymous delegate not allowed
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })()
);

Javascriptで機能する例(比較のため)は次のとおりです。

alert(
    (function(){ return "hello inline anonymous function from javascript"; })()
);

これにより、予期されるアラートボックスが生成されます。

[〜#〜] update [〜#〜]canC#でインライン匿名ラムダを使用できるようです適切にキャストしますが、()の量が手に負えなくなり始めます。

// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))()
);

おそらくコンパイラは、匿名デリゲートのsigを推測して、呼び出しようとしているConsole.WriteLine()を知ることができませんか?この特定のキャストが必要な理由を誰かが知っていますか?

28
Samuel Meacham

C#のラムダには、デリゲート型または式タイプにキャストするコンテキストで使用されるまで、型はありません。だから言えない

var x = () => "some lambda";

あなたは楽しむかもしれません

http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx

22
Brian

型キャストを与えるとうまくいくようです:

String s = ((Func<String>) (() => "hello inline lambda"))();

役に立たないですか?完全ではありません。以下をご覧ください。

String s;
{
    Object o = MightBeNull();
    s = o == null ? "Default value" : o.ToString();
}

今これを考慮してください:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString())
    )(MightBeNull());

少し醜いですが、コンパクトです。

15
sopatt

Func<string> = ...を書き込むと、コンパイラは、タイプFunc<string>のオブジェクトを作成する必要があることを認識します。しかし、そのデリゲートをインラインで作成すると、コンパイラは作成する必要のあるタイプのオブジェクトを認識しません。

上記のことを言っても、明らかな結論を導き出すことができます。コンパイラに型を明示的に伝えるだけです。

Console.WriteLine( new Func<string>( () => "Hello" )() );

[〜#〜] update [〜#〜]

わかりました、私が答えを書いている間に、あなたはあなたの投稿を更新しました。上記の私の答えは、「なぜこの特定のタイプが必要なのか」という質問にすでに答えていると思います。繰り返しになりますが、コンパイラは作成するタイプのオブジェクトを認識していないためです。

ここで、「コンパイラは匿名デリゲートのsigを推測できません」の部分について少し詳しく説明します。ほら、JavaScriptとは違います。 C#には、一般的な「関数」(または「メソッド」)型はありません。各デリゲートには、明示的に指定された署名とタイプ名が必要です。また、デリゲートを作成するとき、コンパイラはどのタイプを知っている必要があります。

これで、匿名オブジェクト型(別名new { a = 1, b = "xyz" })の場合と同様に、コンパイラがその場でデリゲート型を構築できることをどのように示唆できるかがわかります。しかし、少し考えてみてください。とにかく、そのような代理人はおそらく役に立たないでしょう。つまり、別のメソッドに渡すことはできません。そのメソッドは、最初に引数の型を宣言する必要があるためです。また、名前付きの型が必要なため、それからイベントを作成できます。

そんな感じ...

9
Fyodor Soikin

Delegateパラメーターを受け取るメソッドにはインラインラムダ式を使用できます。

ただし、わずかな問題があります。パラメーターが基本のデリゲート型として入力されている場合は、デリゲートの特定の派生(アクションなど)に明示的にキャストする必要があります。そうでなければ、コンパイラは文句を言うでしょう。

同様の質問:
Invoke呼び出しの匿名メソッド
匿名メソッドとデリゲート

2
Gishu