コンパイルしたら、次の間に違いがありますか?
delegate { x = 0; }
そして
() => { x = 0 }
?
短い答え:いいえ。
関係のない長い回答:
Func
やAction
など)に割り当てると、匿名デリゲートが取得されます。編集:式のリンクを次に示します。
私はデビッドの答えが好きですが、私はつまらないと思いました。質問は、「一度コンパイルされる」と言います。これは、両方の式haveがコンパイルされたことを示唆しています。どちらもコンパイルできますが、一方はデリゲートに変換され、もう一方は式ツリーに変換されますか?これは扱いにくいものです。匿名メソッドの別の機能を使用する必要があります。ラムダ式で共有されない唯一のもの。パラメータリストを指定せずに匿名メソッドを指定する場合atこれは、voidを返すデリゲートタイプおよびout
パラメータなしで互換性があります。この知識があれば、2つのオーバーロードを作成して、式を完全に明確にすることができますが、非常に異なるものにすることができます。
しかし、災害が発生します!少なくともC#3.0では、ブロック本体を持つラムダ式を式に変換することはできません。また、本体に代入を持つラムダ式を変換することもできません(戻り値として使用されている場合でも)。これは、C#4.0および.NET 4.0で変更される可能性があり、式ツリーでより多くを表現できます。つまり、MojoFilterがたまたま与えた例では、この2つは常にalmostに変換されます。 (詳細は1分で。)
ただし、ボディを少し変更する場合は、デリゲートパラメータートリックを使用できます。
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
int x = 0;
Foo( () => x );
Foo( delegate { return x; } );
}
static void Foo(Func<int, int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
static void Foo(Expression<Func<int>> func)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
ちょっと待って!十分に巧妙であれば、式ツリーを使用しなくても2つを区別できます。以下の例では、オーバーロード解決ルール(および匿名デリゲートマッチングトリック)を使用しています...
using System;
using System.Linq.Expressions;
public class Base
{
public void Foo(Action action)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
public class Derived : Base
{
public void Foo(Action<int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
int x = 0;
d.Foo( () => { x = 0; } );
d.Foo( delegate { x = 0; } );
}
}
痛い。子供を思い出してください。ベースクラスから継承したメソッドをオーバーロードするたびに、小さな子猫が泣き始めます。
上記の2つの例では、違いはありません、ゼロです。
表現:
() => { x = 0 }
は文本体を持つLambda式であるため、式ツリーとしてコンパイルすることはできません。実際、0の後にセミコロンが必要なため、コンパイルすらしません。
() => { x = 0; } // Lambda statement body
() => x = 0 // Lambda expression body, could be an expression tree.
デビッドBは正しいです。式ツリーを使用することには利点があることに注意してください。 LINQ to SQLは式ツリーを調べ、それをSQLに変換します。
また、ラムダと式ツリーを使用して、リファクタリングに対して安全な方法でフレームワークにクラスメンバーの名前を効果的に渡すこともできます。 Moq はこの例です。