16

outStackOverflow に関するいくつかの C# の質問は、またはrefパラメーターを使用して匿名のデリゲート/ラムダを作成する方法を尋ねます。たとえば、次を参照してください。

これを行うには、次のようにパラメーターの型を指定するだけです。

public void delegate D(out T p);
// ...
D a = (out T t) => { ... };      // Lambda syntax.
D b = delegate(out T t) { ... }; // Anonymous delegate syntax.

私が興味を持っているのは、型が明示的に必要な理由です。これが事実である特定の理由はありますか?つまり、コンパイラ/言語の観点から、次のことが許可されないのはなぜですか?

D a = (out t) => { ... };      // Lambda syntax -- implicit typing.
D b = delegate(out t) { ... }; // Anonymous delegate syntax -- implicit typing.

またはさらに良いのは、次のとおりです。

D a = (t) => { ... };      // Lambda syntax -- implicit typing and ref|out-ness.
D b = delegate(t) { ... }; // Anonymous delegate syntax -- implicit typing and ref|out-ness.
4

2 に答える 2

17

興味深い質問です。

まず、匿名メソッドとラムダの違いを考えてみましょう。コンパイラの作成者の観点から見ると、最も重要な違いは、ラムダでは、ラムダが割り当てられているターゲットからパラメータの型を推論するようコンパイラに要求できることです。C# 2 匿名メソッドには、この機能がありません。この機能は小さな違いのように見えますが、実際にはコンパイラの実装に大きな影響を与えます。その理由については、このトピックに関する私のブログ シリーズを参照してください。

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

それでは、実際の質問に移りましょう。ターゲット型からラムダのパラメーターへの outness/refness を推測できないのはなぜですか。つまり、デリゲート void D(out int x) がある場合、確実に D d = x=> { x = 10; となります。x が「out int」であると推測できます。

なぜそれができなかったのか、私が知っている技術的な理由はありません。コンパイラの内部では、out/ref 型は他の型と同様に表現されます。

ただし、機能は実行できるからといって実行されるわけではありません。そうするやむを得ない理由があるからです。ラムダの場合、最初に型推論を行う説得力のある理由は LINQ です。クエリ内包表記で単純な構文変換をラムダを使用したメソッド呼び出しに実行できるようにしたいと考えており、メソッド型推論エンジンがすべてのラムダ パラメータの型を解決できるようにしたいと考えています。生成された LINQ メソッドには、out または ref パラメーターを持つデリゲートはありません。

したがって、この機能を実行するやむを得ない理由はありません。out/ref パラメーターを持つデリゲートは比較的まれです。そして、これらのデリゲートへのラムダの割り当ては、さらにまれです。したがって、これは私たちが必要としない機能であり、ほとんど誰の利益にもなりません。

C# 3 は、Visual Studio のスケジュールの「長い柱」でした。VS でコンポーネントを出荷するチームの中で、最も多くの作業日数が予定されていました。つまり、私たちが毎日スケジュールを遅らせると、部門全体が遅れることになります。これは、誰の利益にもならない不必要な機能に時間を費やすことへの強力な意欲をそぐものでした。そのため、作業は完了しませんでした。

ここでもっと一貫性があればいいのですが、それが実現する可能性は低いです。私たちにはより高い優先事項がたくさんあります。

于 2010-01-02T20:49:24.677 に答える
2

変数の宣言と割り当てを分割できない理由に関するEricLippertのコメントから:var

原則としてこれが可能であることに同意しますが、実際には、簡単なスケッチが示すよりもかなり複雑です。varは、初期化子が存在することを要求するだけでなく、初期化子が変数を参照しないことも要求します。int M(out int)がある場合は、「int x = M(out x);」と言うことができます。ただし、「var x = M(outx);」とは言えません。Mで過負荷解決を行うには、xのタイプを知る必要があります。これは、私たちが理解しようとしていることです。「vars;if(b)M(out s); else s=0;」と言うのは合法でしょうか。?

たとえば、あなたの質問に対する答えは似ていると思います。

D a = (out var x) => x = M(out x);
于 2010-01-02T04:31:58.297 に答える