it-swarm-tr.com

.NET Framework'teki lambdas ve delegeler arasındaki fark nedir?

Bu soruyu çok sordum ve farkı en iyi nasıl tanımlayacağımızla ilgili bazı girdiler isteyeceğimi düşündüm.

66
ScottKoon

Onlar aslında iki çok farklı şeylerdir. "Delege" aslında bir yönteme veya bir lambdaya atıfta bulunan bir değişkenin adıdır ve bir lambda kalıcı bir adı olmayan bir yöntemdir.

Lambdalar, birkaç ince farklılık dışında, diğer yöntemlere çok benzer.

  1. Normal bir yöntem bir "deyimi" içinde tanımlanır ve kalıcı bir isme bağlanırken, bir lambda "anında" "ifadesi" içinde tanımlanır ve kalıcı adı yoktur.
  2. Bazı lambda'lar .NET ifade ağaçları ile kullanılabilir, oysa ki yöntemler kullanamaz.

Bir temsilci şöyle tanımlanır:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

BinaryIntOp türünde bir değişken, imza aynı olduğu sürece kendisine atanmış bir yöntem veya labmda içerebilir: iki Int32 argümanı ve bir Int32 dönüşü.

Bir lambda şöyle tanımlanabilir:

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

Unutulmaması gereken başka bir şey, genel Func ve Action tipleri genellikle "lambda türleri" olarak kabul edilmelerine rağmen, diğer delegeler gibi olduklarıdır. Onlarla ilgili güzel olan şey, temel olarak ihtiyaç duyabileceğiniz herhangi bir temsilci türü için bir ad tanımlamalarıdır (4 parametreye kadar, kesinlikle kendinize daha fazlasını ekleyebilirsiniz). Bu nedenle, çok çeşitli delege türleri kullanıyorsanız, ancak bir kereden fazla değilse, Func ve Action komutlarını kullanarak kodunuzu delege beyanları ile karıştırmaktan kaçınabilirsiniz.

İşte Func ve Action'ın "sadece lambdalar için değil" olduğuna dair bir örnek:

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

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

Bilinmesi gereken başka bir şey de aynı imzayla delege türlerinin (yöntemlerin kendileri değil), ancak farklı adların birbirine dolaysız olarak verilmeyeceğidir. Bu, Func ve Action delegelerini içerir. Ancak, imza aynıysa, açıkça bunlar arasında yayın yapabilirsiniz.

Ekstra mil gidiyor .... C # fonksiyonlarında, lambda ve delege kullanımı ile esnek. Ancak C # "birinci sınıf fonksiyonlara" sahip değildir. Temelde bu işlevi temsil eden bir nesne oluşturmak için bir temsilci değişkenine atanan bir işlevin adını kullanabilirsiniz. Ama bu gerçekten bir derleyici numarasıdır. İşlev adını yazıp ardından nokta yazarak bir ifade başlatırsanız (yani, işlevin kendisine üye girişi yapmayı deneyin) burada başvuruda bulunacak üye bulunmadığını görürsünüz. Object'ten olanları bile değil. Bu, programcının herhangi bir fonksiyonda çağrılabilecek uzatma yöntemleri eklemek gibi faydalı (ve elbette potansiyel olarak tehlikeli) şeyler yapmasını önler. Yapabileceğiniz en iyi, kesinlikle yararlı olan ama pek de fazla olmayan Delege sınıfını genişletmektir.

Güncelleme: Ayrıca bkz. Karg'ın cevabı isimsiz delegeler ve yöntemler ve lambdalar arasındaki farkı göstermektedir.

Güncelleme 2: James Hart önemli ama çok teknik olmasına rağmen, lambdaların ve delegelerin .NET varlıkları olmadığını (yani CLR'nin delege ya da lambda kavramına sahip olmadığını), daha ziyade çerçeve ve dil olduklarını unutmayın oluşturur.

79
Chris Ammerman

Soru biraz belirsiz, bu da aldığınız cevaplardaki geniş eşitsizliği açıklıyor.

Aslında .NET çerçevesindeki lambdas ve delegeler arasındaki farkın ne olduğunu sordunuz; bu bir çok şeyden biri olabilir. Soruyor musun:

  • C # (veya VB.NET) dilinde lambda ifadeleri ile anonim delegeler arasındaki fark nedir?

  • .NET 3.5'te System.Linq.Expressions.LambdaExpression nesneleri ve System.Delegate nesneleri arasındaki fark nedir?

  • Ya da bu uç noktaların arasında ya da çevresinde bir yer?

Bazı insanlar size çok fazla anlam ifade etmeyen 'C # Lambda ifadeleri ile .NET System.Delegate arasındaki fark nedir?' Sorusunun cevabını vermeye çalışıyor gibi görünüyor.

.NET çerçevesi kendi başına anonim delegeler, lambda ifadeleri veya kapanış kavramlarını anlamamaktadır - bunların hepsi dil spesifikasyonları tarafından tanımlanan şeylerdir. C # derleyicisinin adsız bir yöntemin tanımını, kapatma durumunu korumak için üye değişkenlerle oluşturulan bir sınıftaki bir yönteme nasıl çevirdiğini düşünün; .NET'e delege hakkında isimsiz bir şey yoktur; sadece yazma C # programcısı için anonim. Bu, bir temsilci türüne atanan bir lambda ifadesi için de aynı şekilde geçerlidir.

.NETNE YAPARanlama bir temsilci fikridir - örnekleri belirli nesnelerdeki belirli yöntemlere yapılan sınırsız çağrıları veya belirli bir yöntemdeki sınırsız çağrıları temsil eden bir yöntem imzasını tanımlayan bir tür söz konusu yöntemin söz konusu imzaya bağlı olduğu, söz konusu türdeki herhangi bir nesneye karşı çağrılabilecek belirli bir tür. Bu türlerin tümü System.Delegate'den devralır.

.NET 3.5 ayrıca, kod ifadelerini tanımlamak için sınıflar içeren ve bu nedenle belirli türler veya nesnelerdeki yöntemlere yapılan sınırsız veya sınırsız çağrıları temsil edebilen System.Linq.Expressions ad alanını da sunar. LambdaExpression örnekleri daha sonra gerçek delegelere derlenebilir (burada ifadenin yapısına dayanan dinamik bir yöntem kodlanır ve ona bir temsilci gösterici döndürülür).

C # 'da, çalışma zamanında ifadeyi oluşturmak için uygun kodu üretecek olan söz konusu türdeki bir değişkene bir lambda ifadesi atayarak System.Expressions.Expression türlerinin örneklerini oluşturabilirsiniz.

Tabii ki, eğereğer C # 'da lambda ifadeleri ile adsız yöntemler arasındaki farkın ne olduğunu soruyorsanız, sonuçta, bunların hepsi ilgisizdir ve bu durumda birincil fark kısalıktır; Parametreler umrunda değil ve bir değer döndürmeyi planlamıyorsanız anonim temsilciler ve çıkarımlı parametreler ve dönüş türleri istediğinizde lambdalara doğru karar verirsiniz.

Ve lambda ifadeleri, ifade oluşumunu destekler.

27
James Hart

Bir fark, adsız bir delegenin bir lambda tam imzayla eşleşmesi gerektiğinde parametreleri atlayabilmesidir. Verilen:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

aşağıdaki dört yolla arayabilirsiniz (ikinci satırın herhangi bir parametresi olmayan anonim bir delegeye sahip olduğunu unutmayın):

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;
}

Parametresi olmayan bir lambda ifadesinde veya parametresi olmayan bir yöntemde geçemezsiniz. Bunlara izin verilmiyor:

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

Delegeler işlev işaretçilerine/yöntem işaretçilerine/geri aramalara eşittir (seçiminizi yapın) ve lambdalar oldukça basitleştirilmiş adsız işlevlerdir. En azından insanlara söylediğim bu.

13
Dan Shield

Bununla ilgili bir ton tecrübem yok, ancak bunu tarif edeceğim yol, bir delegenin herhangi bir fonksiyonun etrafındaki bir sarıcı olması, buna karşın bir lambda ifadesinin kendisi anonim bir fonksiyondur.

3
chessguy

Bir temsilci her zaman sadece temel olarak bir işlev işaretçisidir. Bir lambda bir temsilciye dönüşebilir, ancak bir LINQ ifade ağacına da dönüşebilir. Örneğin,

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

İlk satır bir temsilci üretir, ikincisi bir ifade ağacı üretir.

3
Curt Hagenlocher

Bir temsilci, belirli bir parametre listesi ve dönüş türüne sahip bir yönteme yapılan bir referanstır. Bir nesneyi içerebilir veya içermeyebilir.

Bir lambda-ifadesi adsız bir fonksiyon şeklidir.

2
Peter Ritchie

lambdalar delege üzerindeki basitçe sözdizimsel şekerlerdir. Derleyici, lambdaları delegelere dönüştürür.

Bunlar aynı, inanıyorum:

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

Bir temsilci bir işlev imzasıdır; gibi bir şey 

delegate string MyDelegate(int param1);

Delege bir vücut uygulamaz. 

Lambda, delegenin imzasına uyan bir fonksiyon çağrısıdır. Yukarıdaki temsilci için, herhangi birini kullanabilirsiniz;

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

Delegate türüne rağmen kötü bir isim verilir; Delegate türünde bir nesne oluşturmak, aslında işlevleri tutabilecek bir değişken oluşturur - bunlar lambda, statik yöntemler veya sınıf yöntemleri olabilir.

2
Steve Cooper

Sorunun "lambdas ve anonim delegates arasındaki fark nedir?" Olduğu açıktır. Buradaki tüm cevapların dışında sadece bir kişi bunu doğru anladı - asıl fark, lambdaların delegelerin yanı sıra ifade ağaçları oluşturmak için de kullanılabiliyor olmasıdır.

MSDN hakkında daha fazla bilgi edinebilirsiniz: http://msdn.Microsoft.com/en-us/library/bb397687.aspx

2
Philip Beber

Bir temsilci bir işlev işaretçisi sırasıdır, bir temsilci çağırmak birden çok yöntemi çalıştırabilir. Bir lambda esasen, hangi bağlamda kullanıldığına bağlı olarak, derleyici tarafından farklı şekilde yorumlanabilecek isimsiz bir yöntem bildirimidir.

Lambda ifadesini bir delege dökerek bir yöntem olarak işaret eden veya bir derleyicinin sizin için yayınlayacağı belirli bir delege türünü bekleyen bir yönteme parametre olarak geçirirseniz bir temsilci alabilirsiniz. LINQ deyiminin içinde kullanıldığında, lambda derleyici tarafından sadece bir temsilci yerine bir ifade ağacına çevrilecektir.

Aradaki fark, bir lambdanın başka bir ifadenin içindeki bir yöntemi tanımlamanın ters bir yoludur, ancak bir temsilci gerçek bir nesne türüdür.

1
justin.m.chase

Delegeler gerçekten fonksiyonlar için yapısal tiplendirmedir. Aynı şeyi nominal yazma ve bir arabirim veya soyut bir sınıf uygulayan ancak tek bir işlev gerektiğinde çok fazla kod olmasıyla sonuçlanan anonim bir sınıf uygulayarak da yapabilirsiniz.

Lambda, 1930'larda Alonzo Kilisesi'nin lambda matematiği fikrinden gelir. İşlev oluşturmanın adsız bir yoludur. İşlevleri oluşturmak için özellikle yararlı olurlar

Yani bazıları lambda delegeler için sözdizimsel şeker diyebilirken, delegelerin insanları c # ile lambdalara yönlendiren bir köprü olduğunu söyleyebilirim.

1
Steve g

Sorunun belirsizliği nedeniyle, .NET tek başına değil - delege ve lambda ifadelerini anlamada.

A ( normal , generic delegates'in aksine) cf later) delege, bir işlev işaretçisi türünün c + c ++ typedef türü olarak görülmelidir. c ++ örneğinde:

R (*thefunctionpointer) ( T ) ;

typedef, thefunctionpointer türünde bir nesneyi alan ve T türünde bir nesneyi döndüren bir işleve işaretçi türü olan R türüdür. Bunu böyle kullanırsın:

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

thefunction, T alan ve bir R döndüren bir işlev olacaktır.

C # ile giderdin

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

ve bu şekilde kullanırsın:

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

thefunction, T alan ve bir R döndüren bir işlev olacaktır. Bu, delegeler için, normal delegeler olarak adlandırılır.

Şimdi, c # 'da genel delegeleriniz var, ki bunlar jenerik olan delegeler, i.e. bu nedenle "c ++" ifadesini kullanarak "kasıtlı". Böyle tanımlanırlar:

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

Ve onları bu şekilde kullanabilirsiniz:

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);

thefunction2, argüman olarak alan ve double işlevini döndüren bir işlevdir.

Şimdi, thefunction2 yerine, şu anda hiçbir yerde tanımlanmayan, bir deyimle tanımlayan ve daha sonra asla kullanmayacağım bir "işlev" kullanmak istediğimi hayal edin. Daha sonra c #, bu fonksiyonun expression komutunu kullanmamıza izin verir. İfade ile "matematiksel" (ya da programlara sadık işlevsel) ifadesini kastediyorum, örneğin: bir double x için I associate doublex*x. Matematikte bunu "\ mapsto" lateks sembolü kullanarak yazabilirsiniz. C # 'da fonksiyonel gösterim ödünç alınmıştır: =>. Örneğin :

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

(double x) => x * x, bir ifadesi şeklindedir. Bir tür değil, delegeler (genel ya da değil).

Ahlak mı? Sonunda, bir işlev işaretçi türü (değilse, sarılmış + akıllı + genel işlev işaretçisi türü) değilse, bir temsilci (genel. Başka bir şey ! Bkz. this ve that .

İşte benim topal bloguma bir süre dayandığım bir örnek. Çalışan bir iş parçacığındaki bir etiketi güncellemek istediğinizi varsayalım. Delegeler, anon delegeler ve 2 tür lambda kullanarak bu etiketi 1'den 50'ye nasıl güncelleyeceğinize dair 4 örnek aldım.

 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

Buradaki bazı temeller "Delege" aslında bir yönteme veya bir lambdaya referans tutan bir değişkenin adıdır.

Bu anonim bir yöntemdir - (String testString) => {Console.WriteLine (testString); };

Anonim yöntem hiçbir isme sahip olmadığından, bu yöntem ya da ifadenin her ikisini de atayabileceğimiz bir temsilciye ihtiyacımız vardır. Örn.

temsilci boşluğu PrintTestString (string testString); // bir temsilci beyan etmek

PrintTestString print = (string testString) => {Console.WriteLine (testString); }; [. .____] baskı ();


Lambda ifadesi ile aynı. Genellikle onları kullanmak için delege gerekir

s => s.Age> someValue && s.Age <someValue // true/false döndürür

Bu ifadeyi kullanmak için bir işlev delegesi kullanabiliriz.

Func <Öğrenci, bool> checkStudentAge = s => s.Age> someValue && s.Age <someValue;

bool sonucu = checkStudentAge (Öğrenci Nesnesi);

0
Yogesh Prajapati

Lambdalar delegelerin basitleştirilmiş versiyonlarıdır. Bir kapanış benzeri isimsiz delegelerin özelliklerinden bazılarına sahiptirler, fakat aynı zamanda zımni yazı yazmanıza da izin verirler. Bunun gibi bir lambda:

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

bir temsilci ile yapabileceklerinizden çok daha özlüdür:

something.Sort(sortMethod);
...

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