it-swarm.it

Qual è la differenza tra lambda e delegati in .NET Framework?

Ho fatto molte domande e ho pensato di sollecitare qualche input su come descrivere al meglio la differenza.

66
ScottKoon

In realtà sono due cose molto diverse. "Delega" è in realtà il nome di una variabile che contiene un riferimento a un metodo o un lambda e un lambda è un metodo senza nome permanente.

Lambdas è molto simile ad altri metodi, tranne che per un paio di sottili differenze.

  1. Un metodo normale è definito in un "istruzione" e legato a un nome permanente, mentre un lambda è definito "al volo" in un "espressione" e non ha un nome permanente.
  2. Alcuni lambda possono essere usati con alberi di espressioni .NET, mentre i metodi no.

Un delegato è definito in questo modo:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

A una variabile di tipo BinaryIntOp può essere assegnato un metodo o un labmda, purché la firma sia la stessa: due argomenti Int32 e un ritorno Int32.

Un lambda potrebbe essere definito in questo modo:

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

Un'altra cosa da notare è che sebbene i tipi generici di Func e Action sono spesso considerati "tipi di lambda", sono proprio come qualsiasi altro delegato. La cosa bella di loro è che essenzialmente definiscono un nome per qualsiasi tipo di delegato di cui potresti avere bisogno (fino a 4 parametri, anche se puoi sicuramente aggiungerne altri). Pertanto, se si utilizza un'ampia varietà di tipi di delegati, ma non più di una volta, è possibile evitare di ingombrare il codice con dichiarazioni di delegati utilizzando Func e Action.

Ecco un'illustrazione di come Func e Action sono "non solo per lambda":

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

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

Un'altra cosa utile da sapere è che i tipi delegati (non i metodi stessi) con la stessa firma ma nomi diversi non saranno espressi l'uno con l'altro. Questo include i delegati di Func e Action. Tuttavia, se la firma è identica, puoi eseguire il cast esplicito tra di loro.

Andando al massimo ... In C # le funzioni sono flessibili, con l'uso di lambda e delegati. Ma C # non ha "funzioni di prima classe". È possibile utilizzare il nome di una funzione assegnata a una variabile delegata per creare essenzialmente un oggetto che rappresenta tale funzione. Ma è davvero un trucco per i compilatori. Se si avvia una dichiarazione scrivendo il nome della funzione seguito da un punto (vale a dire provare ad accedere ai membri sulla funzione stessa), scoprirai che non ci sono membri a cui fare riferimento. Nemmeno quelli di Object. Questo impedisce al programmatore di fare cose utili (e potenzialmente pericolose ovviamente) come aggiungere metodi di estensione che possono essere chiamati su qualsiasi funzione. Il meglio che puoi fare è estendere la classe Delegate stessa, che è sicuramente anche utile, ma non così tanto.

Aggiornamento: vedi anche la risposta di Karg che illustra la differenza tra delegati anonimi contro metodi e lambda.

Aggiornamento 2: James Hart fa una nota importante, anche se molto tecnica, che lambda e delegati non sono entità .NET (cioè il CLR non ha alcun concetto di delegato o lambda), ma piuttosto sono costrutti di framework e di linguaggio.

79
Chris Ammerman

La domanda è un po 'ambigua, il che spiega l'ampia disparità nelle risposte che stai ricevendo.

In realtà hai chiesto qual è la differenza tra lambdas e delegati nel framework .NET; potrebbe essere una delle tante cose. Stai chiedendo:

  • Qual è la differenza tra espressioni lambda e delegati anonimi nel linguaggio C # (o VB.NET)?

  • Qual è la differenza tra gli oggetti System.Linq.Expressions.LambdaExpression e System.Delegate in .NET 3.5?

  • O qualcosa da qualche parte tra o intorno a questi estremi?

Alcune persone sembrano cercare di darti la risposta alla domanda "qual è la differenza tra le espressioni C # Lambda e .NET System.Delegate?", Che non ha molto senso.

Il framework .NET non comprende di per sé i concetti di delegati anonimi, espressioni lambda o chiusure: sono tutte cose definite dalle specifiche del linguaggio. Pensa a come il compilatore C # traduce la definizione di un metodo anonimo in un metodo su una classe generata con variabili membro per mantenere lo stato di chiusura; su .NET, non c'è nulla di anonimo sul delegato; è solo anonimo al programmatore C # che lo scrive. Ciò vale anche per un'espressione lambda assegnata a un tipo delegato.

Cosa .NETFAcapire è l'idea di un delegato - un tipo che descrive una firma di un metodo, le cui istanze rappresentano o chiamate associate a metodi specifici su oggetti specifici, o chiamate non associate a un particolare metodo su un tipo particolare che può essere invocato contro qualsiasi oggetto di quel tipo, dove detto metodo aderisce alla suddetta firma. Tali tipi ereditano tutti da System.Delegate.

.NET 3.5 introduce anche lo spazio dei nomi System.Linq.Expressions, che contiene classi per la descrizione delle espressioni di codice, e che quindi può anche rappresentare chiamate vincolate o non associate a metodi su particolari tipi o oggetti. Le istanze LambdaExpression possono quindi essere compilate in delegati effettivi (in cui viene codificato un metodo dinamico basato sulla struttura dell'espressione e viene restituito un puntatore delegato ad esso).

In C # è possibile produrre istanze di tipi System.Expressions.Expression assegnando un'espressione lambda a una variabile di tale tipo, che produrrà il codice appropriato per costruire l'espressione in fase di esecuzione.

Certo, se tu were chiedessi quale sia la differenza tra espressioni lambda e metodi anonimi in C #, dopo tutto, allora tutto questo è praticamente irrilevante, e in quel caso la differenza principale è la brevità, che tende verso delegati anonimi quando non si preoccupano dei parametri e non si prevede di restituire un valore, e verso lambdas quando si desidera che i parametri e i tipi restituiti siano di tipo inferito.

E le espressioni lambda supportano la generazione di espressioni.

27
James Hart

Una differenza è che un delegato anonimo può omettere i parametri mentre un lambda deve corrispondere alla firma esatta. Dato:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

puoi chiamarlo nei quattro modi seguenti (nota che la seconda riga ha un delegato anonimo che non ha parametri):

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

Non puoi passare in un'espressione lambda che non ha parametri o un metodo che non ha parametri. Questi non sono ammessi:

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

I delegati sono equivalenti ai puntatori di funzione/ai puntatori del metodo/ai callback (fai la tua scelta), e le lambdas sono funzioni anonimi semplificate. Almeno questo è quello che dico alle persone.

13
Dan Shield

Non ho un sacco di esperienza con questo, ma il modo in cui descriverò è che un delegato è un involucro attorno a qualsiasi funzione, mentre un'espressione lambda è a sua volta una funzione anonima.

3
chessguy

Un delegato è sempre fondamentalmente un puntatore a funzione. Un lambda può trasformarsi in un delegato, ma può anche trasformarsi in un albero di espressioni LINQ. Per esempio,

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

La prima riga produce un delegato, mentre il secondo produce un albero di espressioni.

3
Curt Hagenlocher

Un delegato è un riferimento a un metodo con un particolare elenco di parametri e un tipo di ritorno. Può o non può includere un oggetto.

Un'espressione lambda è una forma di funzione anonima.

2
Peter Ritchie

lambda sono semplicemente zucchero sintattico su un delegato. Il compilatore finisce convertendo lambda in delegati.

Questi sono gli stessi, credo:

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

Un delegato è una firma di funzione; qualcosa di simile a 

delegate string MyDelegate(int param1);

Il delegato non implementa un corpo. 

Il lambda è una chiamata di funzione che corrisponde alla firma del delegato. Per il delegato di cui sopra, è possibile utilizzare qualsiasi di;

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

Il tipo Delegate è mal chiamato, però; la creazione di un oggetto di tipo Delegate crea effettivamente una variabile che può contenere funzioni, siano esse lambdas, metodi statici o metodi di classe.

2
Steve Cooper

È chiaro che la domanda era "qual è la differenza tra lambdas e anonymous delegates?" Di tutte le risposte qui solo una persona ha capito bene - la differenza principale è che lambda può essere utilizzato per creare alberi di espressione e delegati.

Puoi leggere ulteriori informazioni su MSDN: http://msdn.Microsoft.com/en-us/library/bb397687.aspx

2
Philip Beber

Un delegato è un Queue di puntatori a funzione, invocando un delegato può invocare più metodi. Un lambda è essenzialmente una dichiarazione di metodo anonima che può essere interpretata dal compilatore in modo diverso, a seconda del contesto in cui viene utilizzata.

È possibile ottenere un delegato che punti all'espressione lambda come metodo gettandolo in un delegato o, se lo si passa come parametro a un metodo che si aspetta un tipo di delegato specifico, il compilatore lo invierà automaticamente. Usandolo all'interno di una istruzione LINQ, il lambda verrà tradotto dal compilatore in un albero di espressioni anziché semplicemente un delegato.

La differenza è che un lambda è un modo teso per definire un metodo all'interno di un'altra espressione, mentre un delegato è un tipo di oggetto reale.

1
justin.m.chase

I delegati sono in realtà solo digitazione strutturale per le funzioni. Si potrebbe fare la stessa cosa con la digitazione nominale e l'implementazione di una classe anonima che implementa un'interfaccia o una classe astratta, ma questo finisce per essere un sacco di codice quando è necessaria una sola funzione.

Lambda nasce dall'idea del calcolo lambda della Chiesa di Alonzo negli anni '30. È un modo anonimo di creare funzioni. Diventano particolarmente utili per le funzioni di composizione

Quindi, mentre alcuni potrebbero dire che lambda è lo zucchero sintattico per i delegati, direi che i delegati sono un ponte per alleggerire le persone in lambda in c #.

1
Steve g

Presumo che la tua domanda riguardi c # e non .NET, a causa dell'ambiguità della tua domanda, dato che .NET non va da solo - cioè senza c # - comprensione dei delegati e delle espressioni lambda.

A ( normal , in opposizione a così chiamato generic delegates, cf later) delegate dovrebbe essere visto come un tipo di c ++ typedef di un tipo di puntatore a funzione, per istanza in c ++:

R (*thefunctionpointer) ( T ) ;

typedef è il tipo thefunctionpointer che è il tipo di puntatori a una funzione che accetta un oggetto di tipo T e restituisce un oggetto di tipo R. Lo useresti in questo modo:

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

dove thefunction sarebbe una funzione che accetta un T e restituisce un R.

In c # si andrebbe per

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

e lo useresti in questo modo:

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

dove thefunction sarebbe una funzione che accetta un T e restituisce un R. Questo è per i delegati, i cosiddetti delegati normali.

Ora, hai anche delegati generici in c #, che sono delegati generici, i.e. che sono "templati" per così dire, usando quindi un'espressione c ++. Sono definiti così:

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

E puoi usarli in questo modo:

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

dove thefunction2 è una funzione che accetta come argomento e restituisce un double.

Ora immagina che invece di thefunction2 mi piacerebbe usare una "funzione" che non è definita da nessuna parte per ora, da una dichiarazione, e che non userò mai più tardi. Quindi c # ci consente di usare expression di questa funzione. Per espressione intendo l'espressione "matematica" (o funzionale, da attaccare ai programmi), ad esempio: ad un double x I will associate doublex*x. In matematica scrivi questo usando il simbolo "\ mapsto" in lattice . In c # è stata presa in prestito la notazione funzionale: =>. Per esempio :

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

(double x) => x * x è un espressione . Non è un tipo, mentre i delegati (generici o meno) lo sono.

Moralità ? Alla fine, che cos'è un delegato (risp. Delegato generico), se non un tipo di puntatore a funzione (rispetto + smart + tipo di puntatore a funzione generica), eh? Qualcos'altro ! Vedi questo e che .

Ecco un esempio che ho messo un po 'sul mio blog zoppo. Supponi di voler aggiornare un'etichetta da un thread di lavoro. Ho 4 esempi su come aggiornare quell'etichetta da 1 a 50 usando delegati, anon delegati e 2 tipi di 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

"Delegare" è in realtà il nome di una variabile che contiene un riferimento a un metodo o un lambda

Questo è un metodo anonimo - (Stringa testString) => {Console.WriteLine (testString); };

Poiché il metodo anonimo non ha alcun nome, abbiamo bisogno di un delegato nel quale possiamo assegnare entrambi questi metodi o espressioni. Per es.

delegate void PrintTestString (string testString); // dichiara un delegato

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


Lo stesso con l'espressione lambda. Di solito abbiamo bisogno di un delegato per usarli

s => s.Age> someValue && s.Age <someValue // restituirà vero/falso

Possiamo usare un delegato func per usare questa espressione.

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

bool result = checkStudentAge (oggetto studente);

0
Yogesh Prajapati

Lambdas sono versioni semplificate dei delegati. Hanno alcune delle proprietà di un chiusura come i delegati anonimi, ma consentono anche di usare la digitazione implicita. Un lambda come questo:

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

è molto più conciso di quello che puoi fare con un delegato:

something.Sort(sortMethod);
...

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