デリゲートキーワードとラムダ表記


回答:


140

短い答え:いいえ。

関連性がないかもしれない長い答え:

  • ラムダをデリゲートタイプ(FuncまたはなどAction)に割り当てると、匿名のデリゲートが取得されます。
  • ラムダを式タイプに割り当てると、匿名デリゲートの代わりに式ツリーが表示されます。次に、式ツリーを匿名のデリゲートにコンパイルできます。

編集:式のリンクをいくつか示します。

  • System.Linq.Expression.Expression(TDelegate)(ここから開始)。
  • デリゲート(System.Funcなど)を使用したLinqインメモリは、System.Linq.Enumerableを使用します。式を使用したLinq to SQL(およびその他)は、System.Linq.Queryableを使用します。これらのメソッドのパラメーターを確認してください。
  • ScottGuから説明。簡単に言うと、Linqインメモリはクエリを解決するためのいくつかの匿名メソッドを生成します。Linq to SQLは、クエリを表す式ツリーを作成し、そのツリーをT-SQLに変換します。Linq to Entitiesは、クエリを表す式ツリーを生成し、そのツリーをプラットフォームに適したSQLに変換します。

3
式タイプ?これは私にとって新しい領域のように聞こえます。C#で式の型と式ツリーを使用する方法の詳細はどこで確認できますか?
MojoFilter 2008年

2
さらに長い答え-それらが異なるデリゲートタイプに変換できる理由も厄介です:)
Jon Skeet

ラムダは式ラムダである場合、式タイプにのみ割り当てることができることに注意してください。
Micha Wiedenmann、2016年

125

私はエイミーの答えが好きですが、私は知識が豊富だと思いました。「コンパイルされると」という質問は、両方の式コンパイルされたことを示しいます。どちらもコンパイルできますが、1つはデリゲートに、もう1つは式ツリーに変換されますか?これはトリッキーです-匿名メソッドの別の機能を使用する必要があります。ラムダ式で共有されない唯一のもの。パラメーターリストをまったく指定せずに匿名メソッドを指定すると、パラメーターを指定せずにvoidを返す任意のデリゲート型と互換性がありoutます。この知識を武器に、2つのオーバーロードを作成して、式を完全に明確にしますが、非常に異なるものにする必要があります。

しかし、災害が発生しました!少なくともC#3.0では、ブロック本体のラムダ式を式に変換することはできません。また、ボディに代入があるラムダ式を変換することもできません(戻り値として使用されている場合でも)。これは、C#4.0および.NET 4.0で変更される可能性があり、式ツリーでより多くを表現できるようになります。つまり、言い換えれば、MojoFilterがたまたま示した例では、2つはほとんど常に同じものに変換されます。(詳細は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; } );
    }
}

痛い。子供を思い出してください。基本クラスから継承されたメソッドをオーバーロードするたびに、小さな子猫が泣き始めます。


9
ポップコーンを取り出して全部読んだ。それは、私がそれを正面から見つめていても、おそらく決して考えないであろういくつかの違いです。
MojoFilter 2008年

27
私はこれのいくつかを知っていましたが、それを人間に伝えるあなたの能力についてあなたを祝福しなければなりません。
エイミーB

1
.NET 4.0(CT​​Pに基づく)の変更に関心のある方は、marcgravell.blogspot.com/2008/11/future - expressions.htmlを参照してください。C#4.0は、私が知る限り、まだ新しいことは何もしていません。
Marc Gravell

4
ジョン、あなたはロックします。エリック、本当のスキートファンボイになるには、私と同じように彼のスタックオーバーフローrssを購読する必要があります。stackoverflow.com/users/22656をフィードリーダーに貼り付けるだけです。
ポールバトゥーム

3
@RoyiNamir:パラメーターリストなしで匿名メソッドを使用する場合、戻り値の型に互換性がある限り、それは非ref / outパラメーターを持つすべてのデリゲート型と互換性があります。基本的には「パラメータは気にしない」と言っています。と同じでdelegate { ... }ないことに注意してください。delegate() { ... }後者は、パラメーターなしのデリゲート型とのみ互換性があります。
Jon Skeet、2014

2

上記の2つの例では、違いはありません。

表現:

() => { x = 0 }

ステートメント本文を含むラムダ式であるため、式ツリーとしてコンパイルできません。実際、0の後にセミコロンが必要なため、コンパイルすらできません。

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 

6
確かに、「1つはコンパイルされ、もう1つはコンパイルされない」という違いがあることを意味します;)
Jon Skeet

2

エイミーBは正しいです。式ツリーを使用することには利点があることに注意してください。LINQ to SQLは、式ツリーを調べてSQLに変換します。

また、ラムダと式ツリーを使って、クラスメンバーの名前をリファクタリングセーフな方法でフレームワークに効果的に渡すことができます。 Moqはこの例です。


-1

違いがあります

例:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

そして、ラムダ:(エラー)に置き換えます

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

メソッドパラメータのシグネチャが一致しないため、間違った〜lambdaが失敗しました。
Jack Wang

-1

ここにいくつかの基本があります。

これは匿名メソッドです

(string testString) => { Console.WriteLine(testString); };

無名メソッドには名前がないため、これらのメソッドまたは式の両方を割り当てることができるデリゲートが必要です。例えば

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

ラムダ式と同じです。通常、それらを使用するにはデリゲートが必要です

s => s.Age > someValue && s.Age < someValue    // will return true/false

funcデリゲートを使用して、この式を使用できます。

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.