Me hacen mucho esta pregunta y pensé en solicitar alguna opinión sobre cómo describir mejor la diferencia.
Me hacen mucho esta pregunta y pensé en solicitar alguna opinión sobre cómo describir mejor la diferencia.
Respuestas:
En realidad, son dos cosas muy diferentes. "Delegado" es en realidad el nombre de una variable que contiene una referencia a un método o una lambda, y una lambda es un método sin un nombre permanente.
Las lambdas son muy parecidas a otros métodos, excepto por un par de diferencias sutiles.
Un delegado se define así:
delegate Int32 BinaryIntOp(Int32 x, Int32 y);
Una variable de tipo BinaryIntOp puede tener asignado un método o un labmda, siempre que la firma sea la misma: dos argumentos Int32 y un retorno Int32.
Una lambda podría definirse así:
BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
Otra cosa a tener en cuenta es que, aunque los tipos genéricos de Func y Action a menudo se consideran "tipos lambda", son como cualquier otro delegado. Lo bueno de ellos es que esencialmente definen un nombre para cualquier tipo de delegado que pueda necesitar (hasta 4 parámetros, aunque ciertamente puede agregar más de los suyos). Entonces, si está utilizando una amplia variedad de tipos de delegados, pero ninguno más de una vez, puede evitar abarrotar su código con declaraciones de delegado utilizando Func y Action.
Aquí hay una ilustración de cómo Func y Action "no son solo para lambdas":
Int32 DiffOfSquares(Int32 x, Int32 y)
{
return x*x - y*y;
}
Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
Otra cosa útil que debe saber es que los tipos de delegado (no los métodos en sí mismos) con la misma firma pero con nombres diferentes no se transmitirán implícitamente entre sí. Esto incluye a los delegados de Func y Action. Sin embargo, si la firma es idéntica, puede emitir explícitamente entre ellos.
Haciendo un esfuerzo adicional .... En C # las funciones son flexibles, con el uso de lambdas y delegados. Pero C # no tiene "funciones de primera clase". Puede usar el nombre de una función asignado a una variable delegada para crear esencialmente un objeto que represente esa función. Pero es realmente un truco de compilación. Si comienza una declaración escribiendo el nombre de la función seguido de un punto (es decir, intenta hacer acceso a los miembros en la función en sí), encontrará que no hay miembros para hacer referencia. Ni siquiera los de Object. Esto evita que el programador haga cosas útiles (y potencialmente peligrosas, por supuesto) como agregar métodos de extensión que se pueden llamar en cualquier función. Lo mejor que puede hacer es extender la clase Delegate en sí, que seguramente también es útil, pero no tanto.
Actualización: vea también la respuesta de Karg que ilustra la diferencia entre delegados anónimos versus métodos y lambdas.
Actualización 2: James Hart hace una nota importante, aunque muy técnica, de que las lambdas y los delegados no son entidades .NET (es decir, CLR no tiene el concepto de delegado o lambda), sino que son construcciones de marco y lenguaje.
La pregunta es un poco ambigua, lo que explica la gran disparidad en las respuestas que está obteniendo.
De hecho, preguntó cuál es la diferencia entre lambdas y delegados en el marco .NET; esa podría ser una de varias cosas. Estás preguntando:
¿Cuál es la diferencia entre las expresiones lambda y los delegados anónimos en el lenguaje C # (o VB.NET)?
¿Cuál es la diferencia entre los objetos System.Linq.Expressions.LambdaExpression y los objetos System.Delegate en .NET 3.5?
¿O algo en algún lugar entre esos extremos o alrededor de ellos?
Algunas personas parecen estar tratando de darle la respuesta a la pregunta '¿cuál es la diferencia entre las expresiones C # Lambda y .NET System.Delegate?', Lo cual no tiene mucho sentido.
El marco .NET en sí mismo no comprende los conceptos de delegados anónimos, expresiones lambda o cierres; todas esas cosas están definidas por las especificaciones del lenguaje. Piense en cómo el compilador de C # traduce la definición de un método anónimo en un método en una clase generada con variables miembro para mantener el estado de cierre; para .NET, no hay nada anónimo sobre el delegado; es simplemente anónimo para el programador de C # que lo escribe. Eso es igualmente cierto para una expresión lambda asignada a un tipo de delegado.
Lo que .NET SÍ entiende es la idea de un delegado: un tipo que describe la firma de un método, cuyas instancias representan llamadas vinculadas a métodos específicos en objetos específicos o llamadas no vinculadas a un método particular en un tipo particular que se puede invocar contra cualquier objeto de ese tipo, donde dicho método se adhiera a dicha firma. Todos estos tipos heredan de System.Delegate.
.NET 3.5 también presenta el espacio de nombres System.Linq.Expressions, que contiene clases para describir expresiones de código y que, por lo tanto, también puede representar llamadas vinculadas o no vinculadas a métodos en tipos u objetos particulares. Las instancias de LambdaExpression se pueden compilar en delegados reales (mediante el cual se codifica un método dinámico basado en la estructura de la expresión y se devuelve un puntero de delegado).
En C # puede producir instancias de los tipos System.Expressions.Expression asignando una expresión lambda a una variable de dicho tipo, que producirá el código apropiado para construir la expresión en tiempo de ejecución.
Por supuesto, si estabas preguntando cuál es la diferencia entre las expresiones lambda y métodos anónimos en C #, después de todo, entonces todo esto es más o menos irelevant, y en ese caso la diferencia principal es la brevedad, que se inclina hacia los delegados anónimos cuando usted don' No te preocupes por los parámetros y no planeas devolver un valor, y hacia lambdas cuando quieras escribir parámetros inferenciados y tipos de retorno.
Y las expresiones lambda admiten la generación de expresiones.
Una diferencia es que un delegado anónimo puede omitir parámetros, mientras que una lambda debe coincidir con la firma exacta. Dado:
public delegate string TestDelegate(int i);
public void Test(TestDelegate d)
{}
puede llamarlo de las siguientes cuatro formas (tenga en cuenta que la segunda línea tiene un delegado anónimo que no tiene ningún parámetro):
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;
}
No puede pasar una expresión lambda que no tenga parámetros o un método que no tenga parámetros. Estos no están permitidos:
Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature
private string D2()
{
return String.Empty;
}
Los delegados son equivalentes a punteros de función / punteros de método / devoluciones de llamada (elija), y las lambdas son funciones anónimas bastante simplificadas. Al menos eso es lo que le digo a la gente.
Un delegado es siempre básicamente un puntero de función. Una lambda puede convertirse en un delegado, pero también puede convertirse en un árbol de expresión LINQ. Por ejemplo,
Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;
La primera línea produce un delegado, mientras que la segunda produce un árbol de expresión.
lambdas son simplemente azúcar sintáctico en un delegado. El compilador termina convirtiendo lambdas en delegados.
Estos son los mismos, creo:
Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
Delegate
de 'delegado', que es una palabra clave.
Un delegado es una firma de función; algo como
delegate string MyDelegate(int param1);
El delegado no implementa un cuerpo.
La lambda es una llamada a función que coincide con la firma del delegado. Para el delegado anterior, puede usar cualquiera de;
(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";
Sin Delegate
embargo, el tipo está mal nombrado; la creación de un objeto de tipo en Delegate
realidad crea una variable que puede contener funciones, ya sean lambdas, métodos estáticos o métodos de clase.
Un delegado es una referencia a un método con una lista de parámetros y un tipo de retorno particulares. Puede incluir o no un objeto.
Una expresión lambda es una forma de función anónima.
Un delegado es una cola de punteros de función, invocar a un delegado puede invocar varios métodos. Una lambda es esencialmente una declaración de método anónimo que el compilador puede interpretar de manera diferente, dependiendo del contexto en el que se use.
Puede obtener un delegado que apunte a la expresión lambda como un método al convertirlo en un delegado, o si lo pasa como un parámetro a un método que espera un tipo de delegado específico, el compilador lo emitirá por usted. Al usarlo dentro de una declaración LINQ, el compilador traducirá el lambda en un árbol de expresión en lugar de simplemente un delegado.
La diferencia realmente es que una lambda es una forma concisa de definir un método dentro de otra expresión, mientras que un delegado es un tipo de objeto real.
Está bastante claro que la pregunta debía ser "¿cuál es la diferencia entre lambdas y delegados anónimos ?" De todas las respuestas aquí, solo una persona lo hizo bien: la principal diferencia es que las lambdas se pueden usar para crear árboles de expresión y delegados.
Puede leer más en MSDN: http://msdn.microsoft.com/en-us/library/bb397687.aspx
Los delegados son en realidad mecanografía estructural para funciones. Podría hacer lo mismo con la escritura nominal e implementando una clase anónima que implementa una interfaz o clase abstracta, pero eso termina siendo mucho código cuando solo se necesita una función.
Lambda proviene de la idea del cálculo lambda de Alonzo Church en la década de 1930. Es una forma anónima de crear funciones. Se vuelven especialmente útiles para componer funciones.
Entonces, aunque algunos podrían decir que lambda es azúcar sintáctico para los delegados, yo diría que los delegados son un puente para facilitar a las personas el uso de lambdas en c #.
Algunos básicos aquí. "Delegado" es en realidad el nombre de una variable que contiene una referencia a un método o una lambda.
Este es un método anónimo:
(string testString) => { Console.WriteLine(testString); };
Como el método anónimo no tiene ningún nombre, necesitamos un delegado en el que podamos asignar ambos métodos o expresiones. Por ej.
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
Lo mismo con la expresión lambda. Por lo general, necesitamos un delegado para usarlos.
s => s.Age > someValue && s.Age < someValue // will return true/false
Podemos usar un delegado func para usar esta expresión.
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);
Las lambdas son versiones simplificadas de delegados. Tienen algunas de las propiedades de un cierre como los delegados anónimos, pero también le permiten usar la escritura implícita. Una lambda como esta:
something.Sort((x, y) => return x.CompareTo(y));
es mucho más conciso de lo que puede hacer con un delegado:
something.Sort(sortMethod);
...
private int sortMethod(SomeType one, SomeType two)
{
one.CompareTo(two)
}
Aquí hay un ejemplo que puse un rato en mi aburrido blog. Supongamos que desea actualizar una etiqueta de un hilo de trabajo. Tengo 4 ejemplos de cómo actualizar esa etiqueta de 1 a 50 usando delegados, delegados anon y 2 tipos de lambdas.
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);
}
}
Supongo que su pregunta concierne a c # y no a .NET, debido a la ambigüedad de su pregunta, ya que .NET no se queda solo, es decir, sin c #, comprensión de delegados y expresiones lambda.
Un delegado ( normal , en oposición a los llamados delegados genéricos , cf más adelante) debe verse como una especie de c ++ typedef
de un tipo de puntero de función, por ejemplo en c ++:
R (*thefunctionpointer) ( T ) ;
typedef es el tipo thefunctionpointer
que es el tipo de punteros a una función que toma un objeto de tipo T
y devuelve un objeto de tipo R
. Lo usarías así:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
donde thefunction
sería una función tomando un T
y devolviendo un R
.
En c # irías por
delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed
y lo usarías así:
thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T
donde thefunction
sería una función tomando un T
y devolviendo un R
. Esto es para los delegados, los llamados delegados normales.
Ahora, también tiene delegados genéricos en c #, que son delegados que son genéricos, es decir , que tienen "plantillas", por así decirlo, utilizando así una expresión c ++. Se definen así:
public delegate TResult Func<in T, out TResult>(T arg);
Y puedes usarlos así:
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);
donde thefunction2
es una función que toma como argumento y devuelve un double
.
Ahora imagina que, en lugar de, thefunction2
me gustaría usar una "función" que no está definida en ninguna parte por ahora, mediante una declaración, y que nunca usaré más adelante. Entonces c # nos permite usar la expresión de esta función. Por expresión me refiero a la expresión "matemática" (o funcional, para ceñirse a los programas) de la misma, por ejemplo: a un double x
yo asociaré el double
x*x
. En matemáticas, escribe esto usando el símbolo de látex "\ mapsto" . En C # la notación funcional se ha prestado: =>
. Por ejemplo :
Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
// mandatory
(double x) => x * x
es una expresión . No es un tipo, mientras que los delegados (genéricos o no) lo son.
Moralidad? Al final, ¿qué es un delegado (resp. Delegado genérico), si no un tipo de puntero de función (resp. Envuelto + tipo de puntero de función inteligente + genérico), eh? Algo más ! Vea esto y aquello .
Bueno, la versión realmente simplificada es que lambda es una abreviatura de una función anónima. Un delegado puede hacer mucho más que funciones anónimas: cosas como eventos, llamadas asincrónicas y múltiples cadenas de métodos.