it-swarm-id.com

Apa perbedaan antara lambdas dan delegasi dalam .NET Framework?

Saya sering ditanya pertanyaan ini dan saya pikir saya akan meminta beberapa masukan tentang cara terbaik untuk menggambarkan perbedaannya.

66
ScottKoon

Mereka sebenarnya adalah dua hal yang sangat berbeda. "Delegasi" sebenarnya adalah nama untuk variabel yang memiliki referensi ke metode atau lambda, dan lambda adalah metode tanpa nama permanen.

Lambdas sangat mirip dengan metode lain, kecuali untuk beberapa perbedaan halus.

  1. Metode normal didefinisikan dalam "pernyataan" dan diikat ke nama permanen, sedangkan lambda didefinisikan "on the fly" dalam "ekspresi" dan tidak memiliki nama permanen.
  2. Beberapa lambdas dapat digunakan dengan pohon ekspresi .NET, sedangkan metode tidak bisa.

Delegasi didefinisikan seperti ini:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

Variabel tipe BinaryIntOp dapat memiliki metode atau labmda yang ditetapkan untuknya, selama tanda tangannya sama: dua argumen Int32, dan pengembalian Int32.

Lambda mungkin didefinisikan seperti ini:

BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;

Hal lain yang perlu diperhatikan adalah bahwa meskipun fungsi Func dan Action umum sering dianggap "tipe lambda", mereka sama seperti delegasi lainnya. Yang menyenangkan tentang mereka adalah bahwa mereka pada dasarnya menentukan nama untuk semua jenis delegasi yang mungkin Anda butuhkan (hingga 4 parameter, meskipun Anda tentu dapat menambahkan lebih banyak dari Anda sendiri). Jadi jika Anda menggunakan berbagai jenis delegasi, tetapi tidak lebih dari sekali, Anda dapat menghindari mengacaukan kode Anda dengan deklarasi delegasi dengan menggunakan Fungsi dan Aksi.

Berikut ini adalah ilustrasi tentang bagaimana Fungsi dan Aksi "tidak hanya untuk lambdas":

Int32 DiffOfSquares(Int32 x, Int32 y)
{
  return x*x - y*y;
}

Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;

Hal lain yang bermanfaat untuk diketahui adalah bahwa tipe delegasi (bukan metode sendiri) dengan tanda tangan yang sama tetapi nama yang berbeda tidak akan secara implisit dicor satu sama lain. Ini termasuk delegasi Func and Action. Namun jika tanda tangannya identik, Anda dapat secara eksplisit memilih di antara mereka.

Melangkah lebih jauh .... Dalam fungsi C # fleksibel, dengan penggunaan lambdas dan delegasi. Tetapi C # tidak memiliki "fungsi kelas satu". Anda bisa menggunakan nama fungsi yang ditugaskan ke variabel delegasi untuk membuat objek yang mewakili fungsi tersebut. Tapi itu benar-benar trik kompiler. Jika Anda memulai pernyataan dengan menulis nama fungsi diikuti dengan titik (mis. Coba lakukan akses anggota pada fungsi itu sendiri) Anda akan menemukan tidak ada anggota di sana untuk referensi. Bahkan yang dari Object. Ini mencegah programmer dari melakukan hal-hal yang berguna (dan berpotensi berbahaya tentu saja) seperti menambahkan metode ekstensi yang dapat dipanggil pada fungsi apa pun. Yang terbaik yang dapat Anda lakukan adalah memperluas kelas Delegasi itu sendiri, yang tentunya juga bermanfaat, tetapi tidak sebanyak itu.

Pembaruan: Juga lihat Jawaban Karg menggambarkan perbedaan antara delegasi anonim vs metode & lambdas.

Pembaruan 2: James Hart membuat catatan penting, meskipun sangat teknis, bahwa lambdas dan delegasi bukan entitas NET (mis. CLR tidak memiliki konsep delegasi atau lambda), tetapi lebih merupakan kerangka kerja dan konstruksi bahasa.

79
Chris Ammerman

Pertanyaannya sedikit ambigu, yang menjelaskan perbedaan lebar dalam jawaban yang Anda dapatkan.

Anda sebenarnya bertanya apa perbedaan antara lambdas dan delegasi dalam kerangka .NET; itu mungkin salah satu dari sejumlah hal. Apakah Anda bertanya:

  • Apa perbedaan antara ekspresi lambda dan delegasi anonim dalam bahasa C # (atau VB.NET)?

  • Apa perbedaan antara objek System.Linq.Expressions.LambdaExpression dan objek System.Delegate dalam. NET 3.5?

  • Atau sesuatu di suatu tempat di antara atau di sekitar ekstrem itu?

Beberapa orang tampaknya mencoba memberi Anda jawaban atas pertanyaan 'apa perbedaan antara ekspresi C # Lambda dan .NET System.Delegate?', Yang tidak masuk akal.

Kerangka NET. Tidak dengan sendirinya memahami konsep delegasi anonim, ekspresi lambda, atau penutupan - itu semua adalah hal-hal yang ditentukan oleh spesifikasi bahasa. Pikirkan tentang bagaimana kompiler C # menerjemahkan definisi metode anonim menjadi metode pada kelas yang dihasilkan dengan variabel anggota untuk menahan keadaan penutupan; untuk .NET, tidak ada yang anonim tentang delegasi; itu hanya anonim dari programmer C # yang menulisnya. Itu juga berlaku untuk ekspresi lambda yang ditugaskan untuk tipe delegasi.

Apa .NETTIDAKmengerti adalah ide delegasi - jenis yang menggambarkan tanda tangan metode, contoh yang mewakili panggilan terikat ke metode tertentu pada objek tertentu, atau panggilan tidak terikat ke metode tertentu pada tertentu tipe yang dapat dipanggil terhadap objek apa pun dari tipe itu, di mana metode tersebut mematuhi tanda tangan tersebut. Jenis seperti itu semuanya mewarisi dari System.Delegate.

.NET 3.5 juga memperkenalkan namespace System.Linq.Expressions, yang berisi kelas-kelas untuk menggambarkan ekspresi kode - dan yang karenanya juga dapat mewakili panggilan yang terikat atau tidak terikat pada metode pada tipe atau objek tertentu. Contoh-contoh LambdaExpression kemudian dapat dikompilasi menjadi delegasi aktual (di mana metode dinamis berdasarkan pada struktur ekspresi diberi kode, dan penunjuk delegasi untuk itu dikembalikan).

Dalam C # Anda dapat menghasilkan contoh tipe System.Expressions.Expression dengan menetapkan ekspresi lambda ke variabel tipe tersebut, yang akan menghasilkan kode yang sesuai untuk membangun ekspresi saat runtime.

Tentu saja, jika Anda adalah bertanya apa perbedaan antara ekspresi lambda dan metode anonim dalam C #, setelah semua, maka semua ini cukup tidak relevan, dan dalam hal ini perbedaan utama adalah singkatnya, yang condong kepada delegasi anonim ketika Anda tidak peduli tentang parameter dan tidak berencana untuk mengembalikan nilai, dan menuju lambdas ketika Anda ingin mengetik parameter yang disimpulkan dan jenis kembali.

Dan ekspresi lambda mendukung generasi ekspresi.

27
James Hart

Satu perbedaan adalah bahwa delegasi anonim dapat menghilangkan parameter sementara lambda harus cocok dengan tanda tangan yang tepat. Diberikan:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

anda dapat menyebutnya dengan empat cara berikut (perhatikan bahwa baris kedua memiliki delegasi anonim yang tidak memiliki parameter apa pun):

Test(delegate(int i) { return String.Empty; });
Test(delegate { return String.Empty; });
Test(i => String.Empty);
Test(D);

private string D(int i)
{
    return String.Empty;
}

Anda tidak bisa meneruskan dalam ekspresi lambda yang tidak memiliki parameter atau metode yang tidak memiliki parameter. Ini tidak diizinkan:

Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature

private string D2()
{
    return String.Empty;
}
18
Karg

Delegasi setara dengan pointer fungsi/pointer metode/panggilan balik (pilihlah), dan lambdas adalah fungsi anonim yang disederhanakan. Setidaknya itulah yang saya katakan pada orang.

13
Dan Shield

Saya tidak punya banyak pengalaman dalam hal ini, tetapi cara saya menggambarkannya adalah bahwa delegasi adalah pembungkus fungsi apa pun, sedangkan ekspresi lambda sendiri merupakan fungsi anonim.

3
chessguy

Delegasi selalu pada dasarnya hanya sebuah pointer fungsi. Sebuah lambda dapat berubah menjadi delegasi, tetapi juga bisa berubah menjadi pohon ekspresi LINQ. Contohnya,

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

Baris pertama menghasilkan delegasi, sedangkan baris kedua menghasilkan pohon ekspresi.

3
Curt Hagenlocher

Delegasi adalah referensi ke metode dengan daftar parameter tertentu dan tipe pengembalian. Itu mungkin atau mungkin tidak termasuk objek.

Ekspresi lambda adalah bentuk fungsi anonim.

2
Peter Ritchie

lambdas hanyalah gula sintaksis pada seorang delegasi. Kompilator akhirnya mengubah lambdas menjadi delegasi.

Ini sama, saya percaya:

Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
2
Gilligan

Delegasi adalah tanda tangan fungsi; sesuatu seperti 

delegate string MyDelegate(int param1);

Delegasi tidak mengimplementasikan suatu badan. 

Lambda adalah panggilan fungsi yang cocok dengan tanda tangan delegasi. Untuk delegasi di atas, Anda dapat menggunakan salah satu dari;

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

Tipe Delegate diberi nama yang buruk; membuat objek bertipe Delegate sebenarnya menciptakan variabel yang dapat menampung fungsi - baik itu lambdas, metode statis, atau metode kelas.

2
Steve Cooper

Cukup jelas pertanyaannya adalah "apa perbedaan antara lambdas dan anonim delegasi?" Dari semua jawaban di sini hanya satu orang yang benar - perbedaan utama adalah bahwa lambdas dapat digunakan untuk membuat pohon ekspresi serta delegasi.

Anda dapat membaca lebih lanjut di MSDN: http://msdn.Microsoft.com/en-us/library/bb397687.aspx

2
Philip Beber

Delegasi adalah Antrian pointer fungsi, memanggil delegasi dapat meminta beberapa metode. Lambda pada dasarnya adalah deklarasi metode anonim yang dapat ditafsirkan oleh kompiler secara berbeda, tergantung pada konteks apa ia digunakan.

Anda bisa mendapatkan delegasi yang menunjuk ke ekspresi lambda sebagai metode dengan melemparkannya ke delegasi, atau jika meneruskannya sebagai parameter ke metode yang mengharapkan tipe delegasi tertentu, kompiler akan memberikannya untuk Anda. Menggunakannya di dalam pernyataan LINQ, lambda akan diterjemahkan oleh kompiler menjadi pohon ekspresi bukan hanya delegasi.

Perbedaannya sebenarnya adalah bahwa lambda adalah cara singkat untuk mendefinisikan metode di dalam ekspresi lain, sedangkan delegasi adalah tipe objek aktual.

1
justin.m.chase

Delegasi benar-benar hanya mengetik struktural untuk fungsi. Anda bisa melakukan hal yang sama dengan pengetikan nominal dan mengimplementasikan kelas anonim yang mengimplementasikan antarmuka atau kelas abstrak, tetapi yang akhirnya menjadi banyak kode ketika hanya satu fungsi yang diperlukan.

Lambda berasal dari gagasan kalkulus lambda Gereja Alonzo pada 1930-an. Ini adalah cara anonim untuk membuat berbagai fungsi. Mereka menjadi sangat berguna untuk menyusun fungsi

Jadi, sementara beberapa orang mungkin mengatakan lambda adalah gula sintaksis untuk delegasi, saya akan mengatakan delegasi adalah jembatan untuk memudahkan orang menjadi lambda di c #.

1
Steve g

Saya berasumsi bahwa pertanyaan Anda menyangkut c # dan bukan .NET, karena ambiguitas pertanyaan Anda, karena .NET tidak mendapatkan sendiri - yaitu, tanpa c # - pemahaman delegasi dan ekspresi lambda.

A (normal, berlawanan dengan yang disebut generic delegate, cf nanti) delegasi harus dilihat sebagai semacam c ++ typedef dari tipe pointer fungsi, untuk contoh dalam c ++:

R (*thefunctionpointer) ( T ) ;

typedef adalah tipe thefunctionpointer yang merupakan tipe pointer ke fungsi yang mengambil objek bertipe T dan mengembalikan objek tipe R. Anda akan menggunakannya seperti ini:

thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T

di mana thefunction akan berfungsi mengambil T dan mengembalikan R.

Dalam c # Anda akan memilih

delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed

dan Anda akan menggunakannya seperti ini:

thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T

di mana thefunction akan berfungsi mengambil T dan mengembalikan R. Ini untuk delegasi, yang disebut delegasi biasa.

Sekarang, Anda juga memiliki delegasi generik dalam c #, yang merupakan delegasi yang generik, mis. Yang "templated" sehingga untuk berbicara, dengan demikian menggunakan ekspresi c ++. Mereka didefinisikan seperti ini:

public delegate TResult Func<in T, out TResult>(T arg);

Dan Anda dapat menggunakannya seperti ini:

Func<double, double> thefunctor = thefunction2; // call it a functor because it is
                                                // really as a functor that you should
                                                // "see" it
double y = thefunctor(2.0);

di mana thefunction2 adalah fungsi yang mengambil argumen dan mengembalikan double.

Sekarang bayangkan bahwa alih-alih thefunction2 saya ingin menggunakan "fungsi" yang tidak didefinisikan untuk saat ini, dengan pernyataan, dan bahwa saya tidak akan pernah menggunakannya nanti. Kemudian c # memungkinkan kita untuk menggunakan ekspresi dari fungsi ini. Dengan ungkapan yang saya maksud adalah ekspresi "matematika" (atau fungsional, untuk mengikuti program), misalnya: ke double x Saya akan associate the doublex*x. Dalam matematika Anda menulis ini menggunakan simbol lateks "\ mapsto" . Dalam c # notasi fungsional telah dipinjam: =>. Contohnya :

Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
                                                           // mandatory

(double x) => x * x adalah ekspresi . Ini bukan tipe, sedangkan delegasi (generik atau tidak).

Moralitas? Pada akhirnya, apa yang dimaksud dengan delegate (resp. Generic delegate), jika bukan tipe pointer fungsi (resp. Dibungkus + smart + tipe pointer fungsi generik), ya? Sesuatu yang lain Lihat ini dan itu .

Inilah contoh saya memasang beberapa saat di blog lumpuh saya. Katakanlah Anda ingin memperbarui label dari utas pekerja. Saya punya 4 contoh cara memperbarui label itu dari 1 hingga 50 menggunakan delegasi, delegasi langsung dan 2 jenis lambda.

 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); 
         } 
     }
0
Echostorm

Beberapa dasar di sini. "Delegasi" sebenarnya adalah nama untuk variabel yang memiliki referensi ke metode atau lambda

Ini adalah metode anonim - (String testString) => {Console.WriteLine (testString); };

Karena metode anonim tidak memiliki nama apa pun, kami memerlukan delegasi tempat kami dapat menetapkan kedua metode atau ekspresi ini. Untuk Kel.

delegasikan batal PrintTestString (string testString); // nyatakan delegasi

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


Sama dengan ekspresi lambda. Biasanya kita perlu delegasi untuk menggunakannya

s => s.Age> someValue && s.Age <someValue // akan mengembalikan true/false

Kita dapat menggunakan delegate func untuk menggunakan ungkapan ini.

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

hasil bool = checkStudentAge (Obyek Siswa);

0
Yogesh Prajapati

Lambdas adalah versi delegasi yang disederhanakan. Mereka memiliki beberapa properti dari closure seperti delegasi anonim, tetapi juga memungkinkan Anda untuk menggunakan pengetikan tersirat. Seorang lambda menyukai ini:

something.Sort((x, y) => return x.CompareTo(y));

jauh lebih ringkas daripada apa yang dapat Anda lakukan dengan delegasi:

something.Sort(sortMethod);
...

private int sortMethod(SomeType one, SomeType two)
{
    one.CompareTo(two)
}
0
Michael Meadows