[C#] ラムダとデリゲートの違いは何ですか?


Answers

質問は少し曖昧で、あなたが得ている答えには大きな違いがあることが説明されています。

実際には、.NETフレームワークのラムダとデリゲートの違いは何ですか? それは数多くのものの一つかもしれません。 あなたは尋ねている:

  • C#(またはVB.NET)言語のラムダ式と匿名の代理人の違いは何ですか?

  • .NET 3.5のSystem.Linq.Expressions.LambdaExpressionオブジェクトとSystem.Delegateオブジェクトの違いは何ですか?

  • あるいは、その極端な時期やその前後のどこかに?

「C#Lambda式と.NET System.Delegateの違いは何ですか?」という質問に答えようとしている人がいるようですが、それは意味をなさないものです。

.NETフレームワークは、匿名のデリゲート、ラムダ式、またはクロージャーの概念を理解していません。これらはすべて言語仕様で定義されています。 C#コンパイラが、匿名メソッドの定義を、クロージャ状態を保持するメンバ変数を持つ生成されたクラスのメソッドに変換する方法について考えてみましょう。 .NETには、デリゲートについて匿名のものはありません。 それはそれを書いているC#プログラマーにとって匿名です。 これは、デリゲート型に割り当てられたラムダ式についても同様です。

.NETが何を理解するかは、デリゲートのアイデアです。メソッドのシグネチャを記述する型です。インスタンスは、特定のオブジェクトの特定のメソッドへのバインドされた呼び出し、または呼び出される特定の型の特定のメソッドへの呼び出し前記方法が前記署名に従うそのタイプの任意のオブジェクト。 このような型はすべてSystem.Delegateから継承されます。

.NET 3.5では、コード式を記述するためのクラスを含むSystem.Linq.Expressions名前空間も導入されています。したがって、特定の型またはオブジェクトのメソッドへのバインドされた呼び出しまたはバインドされていない呼び出しを表すこともできます。 次に、LambdaExpressionインスタンスを実際のデリゲートにコンパイルすることができます。これにより、式の構造に基づく動的メソッドがcodegennedになり、デリゲートポインタが返されます。

C#では、ラムダ式をその型の変数に代入することでSystem.Expressions.Expression型のインスタンスを生成できます。実行時に式を構築するための適切なコードが生成されます。

もちろん、C#のラムダ式と匿名メソッドの違いが何であるか尋ねていたのであれば、これはすべてかなり哀れなものであり、その場合の主な違いは簡潔であり、匿名の代理人が、パラメータを気にせず、値を返すことを計画しておらず、型推論されたパラメータと戻り値の型を必要とするときはlambdaに向かう。

ラムダ式は式の生成をサポートします。

Question

私はこの質問をたくさん聞かれ、私はその違いを最もよく説明する方法についていくつかの情報を欲しいと思った。




私は私のラメのブログにしばらく置いた例を得ている。 ワーカースレッドからラベルを更新したいとします。 デリゲート、anonデリゲート、および2種類のラムダを使用して、ラベルを1から50に更新する方法の4つの例があります。

 private void button2_Click(object sender, EventArgs e) 
     { 
         BackgroundWorker worker = new BackgroundWorker(); 
         worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
         worker.RunWorkerAsync(); 
     } 

     private delegate void UpdateProgDelegate(int count); 
     private void UpdateText(int count) 
     { 
         if (this.lblTest.InvokeRequired) 
         { 
             UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText); 
             this.Invoke(updateCallBack, new object[] { count }); 
         } 
         else 
         { 
             lblTest.Text = count.ToString(); 
         } 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     {   
         /* Old Skool delegate usage.  See above for delegate and method definitions */ 
         for (int i = 0; i < 50; i++) 
         { 
             UpdateText(i); 
             Thread.Sleep(50); 
         } 

         // Anonymous Method 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((MethodInvoker)(delegate() 
             { 
                 lblTest.Text = i.ToString(); 
             })); 
             Thread.Sleep(50); 
         } 

         /* Lambda using the new Func delegate. This lets us take in an int and 
          * return a string.  The last parameter is the return type. so 
          * So Func<int, string, double> would take in an int and a string 
          * and return a double.  count is our int parameter.*/ 
         Func<int, string> UpdateProgress = (count) => lblTest.Text = count.ToString(); 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke(UpdateProgress, i); 
             Thread.Sleep(50); 
         } 

         /* Finally we have a totally inline Lambda using the Action delegate 
          * Action is more or less the same as Func but it returns void. We could 
          * use it with parameters if we wanted to like this: 
          * Action<string> UpdateProgress = (count) => lblT…*/ 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((Action)(() => lblTest.Text = i.ToString())); 
             Thread.Sleep(50); 
         } 
     }



デリゲートは、基本的には基本的には関数ポインタです。 ラムダはデリゲートに変換できますが、LINQの式ツリーにもなります。 例えば、

Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;

最初の行はデリゲートを生成し、2番目の行は式ツリーを生成します。




まあ、実際には単純すぎるバージョンは、ラムダは無名関数の省略形です。 代理人は、イベント、非同期呼び出し、複数のメソッドチェーンなど、匿名関数以外にも多くのことを行うことができます。




デリゲートは、関数ポインタのキューです。デリゲートを呼び出すと、複数のメソッドを呼び出すことができます。 ラムダは本質的に匿名のメソッド宣言であり、どのようなコンテキストとして使用されているかに応じて、コンパイラによって異なって解釈される可能性があります。

ラムダ式をデリゲートにキャストすることによってラムダ式を指すデリゲートを取得することも、デリゲートを特定のデリゲートタイプが必要なメソッドのパラメータとしてコンパイラが渡すこともできます。 LINQステートメントの内部でそれを使用すると、ラムダは単純にデリゲートではなく式ツリーにコンパイラによって変換されます。

違いは、ラムダは別の式の中にメソッドを定義する簡潔な方法であり、デリゲートは実際のオブジェクト型であるという点です。




デリゲートは関数シグネチャです。 何かのようなもの

delegate string MyDelegate(int param1);

デリゲートはボディを実装していません。

ラムダは、デリゲートの署名と一致する関数呼び出しです。 上記の代理人のために、あなたはいずれかを使うかもしれません。

(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";

ただし、 Delegateタイプの名前は間違っています。 Delegate型のオブジェクトを作成すると、実際にはlambda、静的メソッド、クラスメソッドなどの関数を保持できる変数が作成されます。




質問は「ラムダと匿名の代理人の違いは何ですか? 主な違いは、lambdasを使用して表現ツリーと代理人を作成することができるということです。

MSDNで詳しく読むことができます: http : //msdn.microsoft.com/en-us/library/bb397687.aspx




代理人は関数ポインタ/メソッドポインタ/コールバック(あなたの選択を引き継ぐ)と同等であり、lambdaは非常に単純化された無名関数です。 少なくともそれは私が人々に言うものです。