Saya sering ditanyai pertanyaan ini dan saya pikir saya akan meminta beberapa masukan tentang cara terbaik menjelaskan perbedaannya.
Saya sering ditanyai pertanyaan ini dan saya pikir saya akan meminta beberapa masukan tentang cara terbaik menjelaskan perbedaannya.
Jawaban:
Mereka sebenarnya adalah dua hal yang sangat berbeda. "Delegasi" sebenarnya adalah nama untuk variabel yang menyimpan referensi ke metode atau lambda, dan lambda adalah metode tanpa nama permanen.
Lambda sangat mirip dengan metode lain, kecuali untuk beberapa perbedaan kecil.
Seorang delegasi didefinisikan seperti ini:
delegate Int32 BinaryIntOp(Int32 x, Int32 y);
Variabel tipe BinaryIntOp dapat memiliki metode atau labmda yang ditetapkan, selama tanda tangannya sama: dua argumen Int32, dan kembalian Int32.
Lambda dapat didefinisikan seperti ini:
BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
Hal lain yang perlu diperhatikan adalah meskipun tipe Func dan Action generik sering dianggap sebagai "tipe lambda", mereka sama seperti delegasi lainnya. Hal yang menyenangkan tentang mereka adalah bahwa mereka pada dasarnya menentukan nama untuk semua jenis delegasi yang mungkin Anda perlukan (hingga 4 parameter, meskipun Anda pasti dapat menambahkan lebih banyak dari Anda sendiri). Jadi, jika Anda menggunakan berbagai macam tipe delegasi, tetapi tidak lebih dari sekali, Anda dapat menghindari kekacauan kode Anda dengan deklarasi delegasi dengan menggunakan Func dan Action.
Berikut adalah ilustrasi tentang bagaimana Func dan Action "bukan hanya untuk lambda":
Int32 DiffOfSquares(Int32 x, Int32 y)
{
return x*x - y*y;
}
Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
Hal lain yang berguna untuk diketahui adalah bahwa tipe delegasi (bukan metodenya 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 mentransmisikannya.
Bekerja ekstra .... Dalam fungsi C # fleksibel, dengan penggunaan lambda dan delegasi. Tapi C # tidak memiliki "fungsi kelas satu". Anda dapat menggunakan nama fungsi yang ditetapkan 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 (misalnya, coba lakukan akses anggota pada fungsi itu sendiri), Anda akan menemukan tidak ada anggota di sana yang dapat dirujuk. Bahkan yang dari Object. Hal ini mencegah pemrogram melakukan hal-hal yang berguna (dan berpotensi berbahaya tentunya) seperti menambahkan metode ekstensi yang dapat dipanggil pada fungsi apa pun. Hal terbaik yang dapat Anda lakukan adalah memperluas kelas Delegasi itu sendiri, yang tentunya juga berguna, tetapi tidak terlalu banyak.
Pembaruan: Lihat juga jawaban Karg yang menggambarkan perbedaan antara delegasi anonim vs. metode & lambda.
Pembaruan 2: James Hart membuat catatan penting, meskipun sangat teknis, bahwa lambda dan delegasi bukanlah entitas .NET (yaitu, CLR tidak memiliki konsep delegasi atau lambda), tetapi mereka adalah kerangka kerja dan konstruksi bahasa.
Pertanyaannya agak ambigu, yang menjelaskan perbedaan besar dalam jawaban yang Anda dapatkan.
Anda sebenarnya bertanya apa perbedaan antara lambda dan delegasi dalam kerangka .NET; itu mungkin salah satu dari beberapa 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 di .NET 3.5?
Atau sesuatu 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 terlalu masuk akal.
Kerangka .NET itu sendiri tidak memahami konsep delegasi anonim, ekspresi lambda, atau penutupan - semua itu adalah hal yang ditentukan oleh spesifikasi bahasa. Pikirkan tentang bagaimana compiler C # menerjemahkan definisi metode anonim menjadi metode pada kelas yang dihasilkan dengan variabel anggota untuk menahan status tertutup; ke .NET, tidak ada yang anonim tentang delegasi; itu hanya anonim bagi programmer C # yang menulisnya. Itu sama benarnya dengan ekspresi lambda yang ditugaskan ke tipe delegasi.
Apa .NET TIDAK pahami adalah gagasan delegasi - tipe yang menjelaskan tanda tangan metode, contoh yang mewakili panggilan terikat ke metode tertentu pada objek tertentu, atau panggilan tak terikat ke metode tertentu pada tipe tertentu yang dapat dipanggil objek apa pun dari jenis itu, di mana metode tersebut mengikuti tanda tangan tersebut. Jenis seperti itu semuanya mewarisi dari System.Delegate.
.NET 3.5 juga memperkenalkan namespace System.Linq.Expressions, yang berisi kelas untuk menjelaskan ekspresi kode - dan karena itu juga dapat mewakili panggilan terikat atau tidak terikat ke metode pada jenis atau objek tertentu. Instans LambdaExpression kemudian dapat dikompilasi menjadi delegasi aktual (di mana metode dinamis berdasarkan struktur ekspresi dikodegenkan, dan penunjuk delegasi 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 pada waktu proses.
Tentu saja, jika memang begitu bertanya apa perbedaan antara ekspresi lambda dan metode anonim di C #, setelah semua, maka semua ini cukup banyak irelevant, dan dalam hal bahwa perbedaan utama adalah singkatnya, yang bersandar ke arah delegasi anonim ketika Anda don' t peduli tentang parameter dan tidak berencana untuk mengembalikan nilai, dan menuju lambda saat Anda ingin mengetikkan parameter yang dirujuk dan jenis kembalian.
Dan ekspresi lambda mendukung pembuatan ekspresi.
Satu perbedaan adalah 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 memanggilnya 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 dapat meneruskan ekspresi lambda yang tidak memiliki parameter atau metode yang tidak memiliki parameter. Ini tidak diperbolehkan:
Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature
private string D2()
{
return String.Empty;
}
Delegasi setara dengan function pointers / method pointers / callbacks (pilihlah), dan lambda adalah fungsi anonim yang cukup disederhanakan. Setidaknya itulah yang saya katakan kepada orang-orang.
Delegasi pada dasarnya selalu merupakan penunjuk fungsi. Lambda bisa berubah menjadi delegasi, tetapi juga bisa berubah menjadi pohon ekspresi LINQ. Misalnya,
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.
lambda hanyalah gula sintaksis pada delegasi. Kompilator akhirnya mengubah lambda menjadi delegasi.
Ini sama, saya percaya:
Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
Delegate
dari 'delegate', yang merupakan kata kunci.
Delegasi adalah tanda tangan fungsi; sesuatu seperti
delegate string MyDelegate(int param1);
Delegasi tidak mengimplementasikan 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";
The Delegate
Tipe parah bernama, meskipun; membuat objek bertipe Delegate
sebenarnya membuat variabel yang dapat menampung fungsi - baik itu lambda, metode statis, atau metode kelas.
Delegasi adalah referensi ke metode dengan daftar parameter tertentu dan tipe kembalian. Ini mungkin atau mungkin tidak termasuk objek.
Ekspresi lambda adalah bentuk fungsi anonim.
Delegasi adalah Antrian penunjuk fungsi, memanggil delegasi dapat memanggil beberapa metode. Lambda pada dasarnya adalah deklarasi metode anonim yang dapat diinterpretasikan oleh kompilator secara berbeda, tergantung pada konteks apa ia digunakan.
Anda bisa mendapatkan delegasi yang menunjuk ke ekspresi lambda sebagai metode dengan mentransmisikannya ke dalam delegasi, atau jika meneruskannya sebagai parameter ke metode yang mengharapkan tipe delegasi tertentu kompilator akan mentransmisikannya untuk Anda. Menggunakannya di dalam pernyataan LINQ, lambda akan diterjemahkan oleh kompilator menjadi pohon ekspresi, bukan hanya sebuah delegasi.
Perbedaan sebenarnya adalah lambda adalah cara singkat untuk mendefinisikan metode di dalam ekspresi lain, sedangkan delegasi adalah tipe objek yang sebenarnya.
Cukup jelas bahwa pertanyaannya adalah "apa perbedaan antara lambda dan delegasi anonim ?" Dari semua jawaban di sini, hanya satu orang yang benar - perbedaan utamanya adalah lambda dapat digunakan untuk membuat pohon ekspresi serta delegasi.
Anda dapat membaca lebih lanjut di MSDN: http://msdn.microsoft.com/en-us/library/bb397687.aspx
Delegasi sebenarnya hanyalah pengetikan struktural untuk fungsi. Anda dapat melakukan hal yang sama dengan pengetikan nominal dan mengimplementasikan kelas anonim yang mengimplementasikan antarmuka atau kelas abstrak, tetapi itu akan menjadi banyak kode ketika hanya satu fungsi yang dibutuhkan.
Lambda berasal dari ide kalkulus lambda dari Gereja Alonzo pada tahun 1930-an. Ini adalah cara anonim untuk membuat 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 #.
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, kami memerlukan delegasi tempat kami dapat menetapkan kedua metode atau ekspresi ini. Untuk Ex.
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
Sama dengan ekspresi lambda. Biasanya kami membutuhkan delegasi untuk menggunakannya
s => s.Age > someValue && s.Age < someValue // will return true/false
Kita dapat menggunakan sebuah func delegate untuk menggunakan ekspresi ini.
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);
Lambdas adalah versi delegasi yang disederhanakan. Mereka memiliki beberapa properti closure seperti delegasi anonim, tetapi juga memungkinkan Anda menggunakan pengetikan tersirat. Lambda seperti ini:
something.Sort((x, y) => return x.CompareTo(y));
jauh lebih ringkas daripada yang dapat Anda lakukan dengan seorang delegasi:
something.Sort(sortMethod);
...
private int sortMethod(SomeType one, SomeType two)
{
one.CompareTo(two)
}
Inilah contoh yang saya pasang di blog saya yang lumpuh. Katakanlah Anda ingin memperbarui label dari utas pekerja. Saya punya 4 contoh cara memperbarui label itu dari 1 menjadi 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);
}
}
Saya berasumsi bahwa pertanyaan Anda menyangkut c # dan bukan. NET, karena ambiguitas pertanyaan Anda, karena. NET tidak sendirian - yaitu, tanpa c # - pemahaman delegasi dan ekspresi lambda.
A ( normal , berlawanan dengan apa yang disebut delegasi generik , cf later) delegasi harus dilihat sebagai jenis c ++ typedef
dari tipe penunjuk fungsi, misalnya di c ++:
R (*thefunctionpointer) ( T ) ;
typedef adalah tipe thefunctionpointer
yang merupakan tipe pointer ke fungsi yang mengambil objek bertipe T
dan mengembalikan objek bertipe R
. Anda akan menggunakannya seperti ini:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
di mana thefunction
akan menjadi fungsi yang mengambil T
dan mengembalikan R
.
Dalam c # Anda akan pergi
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 menjadi fungsi yang mengambil T
dan mengembalikan R
. Ini untuk delegasi, yang disebut delegasi biasa.
Sekarang, Anda juga memiliki delegasi generik di c #, yang merupakan delegasi yang generik, misalnya yang "menggunakan template", 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
fungsi mengambil sebagai argumen dan mengembalikan a double
.
Sekarang bayangkan bahwa alih-alih thefunction2
saya ingin menggunakan "fungsi" yang tidak didefinisikan di mana pun untuk saat ini, dengan pernyataan, dan yang tidak akan pernah saya gunakan nanti. Kemudian c # mengijinkan kita untuk menggunakan ekspresi dari fungsi ini. Dengan ekspresi Maksudku "matematika" (atau fungsional, untuk tetap program) ekspresi itu, misalnya: ke double x
saya akan mengasosiasikan dengan double
x*x
. Dalam matematika Anda menulis ini menggunakan simbol lateks "\ mapsto" . Dalam c # notasi fungsional telah dipinjam: =>
. Misalnya :
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) adalah.
Moralitas? Pada akhirnya, apa itu delegate (resp. Generic delegate), jika bukan tipe penunjuk fungsi (resp. Dibungkus + jenis penunjuk fungsi pintar + generik), ya? Sesuatu yang lain! Lihat ini dan itu .
Nah, versi yang sangat disederhanakan adalah lambda hanyalah singkatan dari fungsi anonim. Delegasi dapat melakukan lebih dari sekadar fungsi anonim: hal-hal seperti acara, panggilan asinkron, dan beberapa rantai metode.