Diese Frage wird mir oft gestellt und ich dachte, ich würde um Input bitten, wie ich den Unterschied am besten beschreiben kann.
Diese Frage wird mir oft gestellt und ich dachte, ich würde um Input bitten, wie ich den Unterschied am besten beschreiben kann.
Antworten:
Sie sind eigentlich zwei sehr unterschiedliche Dinge. "Delegieren" ist eigentlich der Name für eine Variable, die einen Verweis auf eine Methode oder ein Lambda enthält, und ein Lambda ist eine Methode ohne permanenten Namen.
Lambdas sind anderen Methoden sehr ähnlich, mit Ausnahme einiger subtiler Unterschiede.
Ein Delegat ist wie folgt definiert:
delegate Int32 BinaryIntOp(Int32 x, Int32 y);
Einer Variablen vom Typ BinaryIntOp kann entweder eine Methode oder ein Labmda zugewiesen werden, sofern die Signatur identisch ist: zwei Int32-Argumente und eine Int32-Rückgabe.
Ein Lambda könnte folgendermaßen definiert werden:
BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
Eine andere zu beachtende Sache ist, dass die generischen Func- und Action-Typen oft als "Lambda-Typen" betrachtet werden, aber genau wie alle anderen Delegierten sind. Das Schöne an ihnen ist, dass sie im Wesentlichen einen Namen für jede Art von Delegat definieren, die Sie möglicherweise benötigen (bis zu 4 Parameter, obwohl Sie sicherlich mehr eigene hinzufügen können). Wenn Sie also eine Vielzahl von Delegatentypen verwenden, jedoch nicht mehr als einmal, können Sie mithilfe von Func und Action vermeiden, dass Ihr Code mit Delegatdeklarationen überladen wird.
Hier ist ein Beispiel dafür, wie Func und Action "nicht nur für Lambdas" sind:
Int32 DiffOfSquares(Int32 x, Int32 y)
{
return x*x - y*y;
}
Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
Eine weitere nützliche Information ist, dass Delegatentypen (nicht Methoden selbst) mit derselben Signatur, aber unterschiedlichen Namen nicht implizit ineinander umgewandelt werden. Dies schließt die Func- und Action-Delegierten ein. Wenn die Signatur jedoch identisch ist, können Sie explizit zwischen ihnen wechseln.
Die Extrameile gehen ... In C # sind Funktionen flexibel, mit der Verwendung von Lambdas und Delegierten. C # hat jedoch keine "erstklassigen Funktionen". Sie können den einer Delegatenvariablen zugewiesenen Funktionsnamen verwenden, um im Wesentlichen ein Objekt zu erstellen, das diese Funktion darstellt. Aber es ist wirklich ein Compilertrick. Wenn Sie eine Anweisung beginnen, indem Sie den Funktionsnamen gefolgt von einem Punkt schreiben (dh versuchen, einen Mitgliederzugriff auf die Funktion selbst durchzuführen), werden Sie feststellen, dass dort keine Mitglieder vorhanden sind, auf die verwiesen werden kann. Nicht einmal die von Object. Dies verhindert, dass der Programmierer nützliche (und natürlich möglicherweise gefährliche) Dinge ausführt, z. B. das Hinzufügen von Erweiterungsmethoden, die für jede Funktion aufgerufen werden können. Das Beste, was Sie tun können, ist, die Delegate-Klasse selbst zu erweitern, was sicherlich auch nützlich ist, aber nicht ganz so viel.
Update: Siehe auch Kargs Antwort die den Unterschied zwischen anonymen Delegierten und Methoden und Lambdas veranschaulicht.
Update 2: James Hart macht einen wichtigen, wenn auch sehr technischen Hinweis darauf, dass Lambdas und Delegaten keine .NET-Entitäten sind (dh die CLR hat kein Konzept für einen Delegaten oder ein Lambda), sondern Framework- und Sprachkonstrukte.
Die Frage ist etwas mehrdeutig, was die große Ungleichheit bei den Antworten erklärt, die Sie erhalten.
Sie haben tatsächlich gefragt, was der Unterschied zwischen Lambdas und Delegaten im .NET Framework ist. das könnte eines von vielen Dingen sein. Fragst du:
Was ist der Unterschied zwischen Lambda-Ausdrücken und anonymen Delegaten in der Sprache C # (oder VB.NET)?
Was ist der Unterschied zwischen System.Linq.Expressions.LambdaExpression-Objekten und System.Delegate-Objekten in .NET 3.5?
Oder etwas irgendwo zwischen oder um diese Extreme?
Einige Leute scheinen zu versuchen, Ihnen die Antwort auf die Frage "Was ist der Unterschied zwischen C # Lambda-Ausdrücken und .NET System.Delegate?" Zu geben, was nicht viel Sinn macht.
Das .NET Framework versteht an sich nicht die Konzepte anonymer Delegaten, Lambda-Ausdrücke oder Schließungen - all dies wird durch Sprachspezifikationen definiert. Überlegen Sie, wie der C # -Compiler die Definition einer anonymen Methode in eine Methode für eine generierte Klasse mit Mitgliedsvariablen übersetzt, um den Abschlussstatus beizubehalten. Für .NET ist der Delegat nicht anonym. Es ist nur anonym für den C # -Programmierer, der es schreibt. Dies gilt auch für einen Lambda-Ausdruck, der einem Delegatentyp zugewiesen ist.
Was .NET DOES verstehen , ist die Idee eines Delegierten - ein Typ, der eine Methodensignatur beschreibt, Instanzen , von denen entweder darstellen Anrufe auf bestimmte Methoden auf bestimmte Objekte gebunden oder ungebunden Anrufe an eine bestimmte Methode auf einen bestimmten Typ, der gegen aufgerufen werden kann jedes Objekt dieses Typs, bei dem das Verfahren der Signatur entspricht. Solche Typen erben alle von System.Delegate.
In .NET 3.5 wird außerdem der System.Linq.Expressions-Namespace eingeführt, der Klassen zur Beschreibung von Codeausdrücken enthält und daher auch gebundene oder ungebundene Aufrufe von Methoden für bestimmte Typen oder Objekte darstellen kann. LambdaExpression-Instanzen können dann zu tatsächlichen Delegaten kompiliert werden (wobei eine dynamische Methode, die auf der Struktur des Ausdrucks basiert, codegenniert und ein Delegatenzeiger darauf zurückgegeben wird).
In C # können Sie Instanzen von System.Expressions.Expression-Typen erstellen, indem Sie einer Variablen dieses Typs einen Lambda-Ausdruck zuweisen, der den entsprechenden Code zum Erstellen des Ausdrucks zur Laufzeit erzeugt.
Natürlich, wenn Sie wurden gefragt , was der Unterschied zwischen Lambda - Ausdrücke und anonymen Methoden in C # ist, nach allem, dann ist das alles ziemlich irelevant, und in diesem Fall ist der Hauptunterschied der Kürze, der lehnt dich in Richtung anonym Delegierten , wenn Sie don‘ Sie kümmern sich nicht um Parameter und planen nicht, einen Wert zurückzugeben, und in Richtung Lambdas, wenn Sie abgeleitete Parameter und Rückgabetypen eingeben möchten.
Und Lambda-Ausdrücke unterstützen die Ausdrucksgenerierung.
Ein Unterschied besteht darin, dass ein anonymer Delegat Parameter weglassen kann, während ein Lambda mit der genauen Signatur übereinstimmen muss. Gegeben:
public delegate string TestDelegate(int i);
public void Test(TestDelegate d)
{}
Sie können es auf die folgenden vier Arten aufrufen (beachten Sie, dass die zweite Zeile einen anonymen Delegaten hat, der keine Parameter hat):
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;
}
Sie können keinen Lambda-Ausdruck ohne Parameter oder eine Methode ohne Parameter übergeben. Diese sind nicht erlaubt:
Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature
private string D2()
{
return String.Empty;
}
Delegaten entsprechen Funktionszeigern / Methodenzeigern / Rückrufen (treffen Sie Ihre Wahl), und Lambdas sind ziemlich vereinfachte anonyme Funktionen. Zumindest sage ich das den Leuten.
Ich habe nicht viel Erfahrung damit, aber ich würde es so beschreiben, dass ein Delegat ein Wrapper um jede Funktion ist, während ein Lambda-Ausdruck selbst eine anonyme Funktion ist.
Ein Delegat ist im Grunde immer nur ein Funktionszeiger. Ein Lambda kann sich in einen Delegaten verwandeln, aber es kann sich auch in einen LINQ-Ausdrucksbaum verwandeln. Zum Beispiel,
Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;
Die erste Zeile erzeugt einen Delegaten, während die zweite einen Ausdrucksbaum erzeugt.
Lambdas sind einfach syntaktischer Zucker für einen Delegierten. Der Compiler konvertiert schließlich Lambdas in Delegaten.
Ich glaube, das sind die gleichen:
Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
Delegate
von 'delegate' ändern , was ein Schlüsselwort ist.
Ein Delegat ist eine Funktionssignatur. etwas wie
delegate string MyDelegate(int param1);
Der Delegierte implementiert kein Gremium.
Das Lambda ist ein Funktionsaufruf, der der Signatur des Delegaten entspricht. Für den oben genannten Delegaten können Sie eine der folgenden Optionen verwenden:
(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";
Der Delegate
Typ ist jedoch schlecht benannt; Durch das Erstellen eines Objekts vom Typ wird Delegate
tatsächlich eine Variable erstellt, die Funktionen enthalten kann - seien es Lambdas, statische Methoden oder Klassenmethoden.
Ein Delegat ist eine Referenz auf eine Methode mit einer bestimmten Parameterliste und einem bestimmten Rückgabetyp. Es kann ein Objekt enthalten oder nicht.
Ein Lambda-Ausdruck ist eine Form der anonymen Funktion.
Ein Delegat ist eine Warteschlange mit Funktionszeigern. Beim Aufrufen eines Delegaten können mehrere Methoden aufgerufen werden. Ein Lambda ist im Wesentlichen eine anonyme Methodendeklaration, die vom Compiler je nach verwendetem Kontext unterschiedlich interpretiert werden kann.
Sie können einen Delegaten erhalten, der auf den Lambda-Ausdruck als Methode verweist, indem Sie ihn in einen Delegaten umwandeln. Wenn Sie ihn als Parameter an eine Methode übergeben, die einen bestimmten Delegatentyp erwartet, wird er vom Compiler für Sie umgewandelt. Wenn Sie es in einer LINQ-Anweisung verwenden, wird das Lambda vom Compiler in einen Ausdrucksbaum anstatt nur in einen Delegaten übersetzt.
Der Unterschied besteht darin, dass ein Lambda eine knappe Möglichkeit ist, eine Methode innerhalb eines anderen Ausdrucks zu definieren, während ein Delegat ein tatsächlicher Objekttyp ist.
Es ist ziemlich klar, dass die Frage lauten sollte: "Was ist der Unterschied zwischen Lambdas und anonymen Delegierten?" Von allen Antworten hier hat nur eine Person es richtig verstanden - der Hauptunterschied besteht darin, dass Lambdas sowohl zum Erstellen von Ausdrucksbäumen als auch von Delegierten verwendet werden können.
Weitere Informationen finden Sie auf MSDN: http://msdn.microsoft.com/en-us/library/bb397687.aspx
Delegierte sind wirklich nur strukturelle Typisierung für Funktionen. Sie können dasselbe mit der nominalen Eingabe und Implementierung einer anonymen Klasse tun, die eine Schnittstelle oder eine abstrakte Klasse implementiert. Dies ist jedoch eine Menge Code, wenn nur eine Funktion benötigt wird.
Lambda stammt aus der Idee des Lambda-Kalküls der Alonzo-Kirche in den 1930er Jahren. Es ist eine anonyme Methode zum Erstellen von Funktionen. Sie werden besonders nützlich zum Erstellen von Funktionen
Während einige sagen könnten, Lambda sei syntaktischer Zucker für Delegierte, würde ich sagen, dass Delegierte eine Brücke sind, um Menschen in c # zu Lambdas zu bringen.
Einige grundlegende hier. "Delegieren" ist eigentlich der Name für eine Variable, die einen Verweis auf eine Methode oder ein Lambda enthält
Dies ist eine anonyme Methode -
(string testString) => { Console.WriteLine(testString); };
Da anonyme Methoden keinen Namen haben, benötigen wir einen Delegaten, in dem wir beide Methoden oder Ausdrücke zuweisen können. Zum Beispiel.
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
Gleiches gilt für den Lambda-Ausdruck. Normalerweise brauchen wir einen Delegierten, um sie zu benutzen
s => s.Age > someValue && s.Age < someValue // will return true/false
Wir können einen func-Delegaten verwenden, um diesen Ausdruck zu verwenden.
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);
Lambdas sind vereinfachte Versionen von Delegierten. Sie haben einige der Eigenschaften eines Abschlusses wie anonyme Delegaten, ermöglichen Ihnen jedoch auch die Verwendung der impliziten Eingabe. Ein Lambda wie dieses:
something.Sort((x, y) => return x.CompareTo(y));
ist viel prägnanter als das, was Sie mit einem Delegierten tun können:
something.Sort(sortMethod);
...
private int sortMethod(SomeType one, SomeType two)
{
one.CompareTo(two)
}
Hier ist ein Beispiel, das ich eine Weile in meinem lahmen Blog veröffentlicht habe. Angenommen, Sie möchten ein Etikett aus einem Arbeitsthread aktualisieren. Ich habe 4 Beispiele, wie dieses Label mithilfe von Delegaten, anon-Delegierten und 2 Arten von Lambdas von 1 auf 50 aktualisiert werden kann.
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);
}
}
Ich gehe davon aus, dass Ihre Frage aufgrund der Mehrdeutigkeit Ihrer Frage c # und nicht .NET betrifft, da .NET nicht alleine ist - dh ohne c # - Verständnis von Delegaten und Lambda-Ausdrücken.
Ein ( normaler , im Gegensatz zu sogenannten generischen Delegaten, siehe später) Delegat sollte als eine Art c ++ typedef
eines Funktionszeigertyps angesehen werden, beispielsweise in c ++:
R (*thefunctionpointer) ( T ) ;
typedef ist der Typ, thefunctionpointer
der der Zeigertyp auf eine Funktion ist, die ein Objekt vom Typ nimmt T
und ein Objekt vom Typ zurückgibt R
. Sie würden es so verwenden:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
wo thefunction
wäre eine Funktion eine Aufnahme T
und Rückkehr ein R
.
In c # würden Sie für gehen
delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed
und du würdest es so benutzen:
thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T
wo thefunction
wäre eine Funktion eine Aufnahme T
und Rückkehr ein R
. Dies gilt für Delegierte, sogenannte normale Delegierte.
Jetzt haben Sie auch generische Delegaten in c #, bei denen es sich um generische Delegaten handelt, dh die sozusagen "Vorlagen" sind, wobei ein c ++ - Ausdruck verwendet wird. Sie sind wie folgt definiert:
public delegate TResult Func<in T, out TResult>(T arg);
Und Sie können sie so verwenden:
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);
wo thefunction2
nimmt eine Funktion als Argument und eine Rückkehr double
.
Stellen Sie sich nun vor, dass thefunction2
ich stattdessen eine "Funktion" verwenden möchte, die im Moment nirgends durch eine Anweisung definiert ist und die ich später nie mehr verwenden werde. Dann erlaubt uns c #, den Ausdruck dieser Funktion zu verwenden. Mit dem Ausdruck meine ich die „mathematische“ (oder funktional, um Programme zu bleiben) Ausdruck davon, zum Beispiel: zu a double x
Ich werde assoziieren die double
x*x
. In der Mathematik schreiben Sie dies mit dem Latexsymbol "\ mapsto" . In c # wurde die funktionale Notation ausgeliehen : =>
. Zum Beispiel :
Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
// mandatory
(double x) => x * x
ist ein Ausdruck . Es ist kein Typ, wohingegen Delegierte (generisch oder nicht) sind.
Moral? Was ist am Ende ein Delegat (bzw. generischer Delegat), wenn nicht ein Funktionszeigertyp (bzw. verpackter + intelligenter + generischer Funktionszeigertyp)? Etwas anderes ! Sehen Sie dies und das .
Nun, die wirklich vereinfachte Version ist, dass ein Lambda nur eine Abkürzung für eine anonyme Funktion ist. Ein Delegat kann viel mehr als nur anonyme Funktionen ausführen: Ereignisse, asynchrone Aufrufe und mehrere Methodenketten.