method expresiones ejemplos delegate c# .net delegates lambda anonymous-methods

c# - expresiones - delegar palabra clave vs. notación lambda



if lambda c# (6)

Algunos básicos aquí.

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.

delegar void PrintTestString (string testString); // declaro un delegado

PrintTestString print = (string testString) => {Console.WriteLine (testString); }; impresión();

Lo mismo con la expresión lambda. Usualmente necesitamos delegar para usarlos

s => s.Age> someValue && s.Age <algúnValor // devolverá verdadero / falso

Podemos usar un delegado de func para usar esta expresión.

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

bool result = checkStudentAge (Student Object);

Una vez que se compila, ¿hay alguna diferencia entre:

delegate { x = 0; }

y

() => { x = 0 }

?


David B es correcto. Tenga en cuenta que puede haber ventajas al usar árboles de expresiones. LINQ to SQL examinará el árbol de expresiones y lo convertirá en SQL.

También puede jugar trucos con lamdas y árboles de expresión para pasar efectivamente los nombres de los miembros de la clase a un marco de trabajo en una forma de refactorización segura. Moq es un ejemplo de esto.


En los dos ejemplos anteriores, no hay diferencia, cero.

La expresion:

() => { x = 0 }

es una expresión Lambda con cuerpo de declaración, por lo que no se puede compilar como un árbol de expresiones. De hecho, ni siquiera compila porque necesita un punto y coma después de 0:

() => { x = 0; } // Lambda statement body () => x = 0 // Lambda expression body, could be an expression tree.


Hay una diferencia

Ejemplo:

var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(delegate { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); });

Y lo reemplazo con lambda: (error)

var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(()=> { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); });


Me gusta la respuesta de David, pero pensé que sería pedante. La pregunta dice, "Una vez que se compila", lo que sugiere que ambas expresiones se han compilado. ¿Cómo podrían ambos compilar, pero convirtiendo uno en un delegado y uno en un árbol de expresiones? Es complicado: tienes que usar otra característica de los métodos anónimos; el único que no es compartido por expresiones lambda. Si especifica un método anónimo sin especificar una lista de parámetros, es compatible con cualquier tipo de delegado que devuelva vacío y sin ningún parámetro de out . Armados con este conocimiento, deberíamos poder construir dos sobrecargas para hacer que las expresiones sean completamente inequívocas pero muy diferentes.

Pero el desastre golpea! Al menos con C # 3.0, no puede convertir una expresión lambda con un cuerpo de bloque en una expresión, ni puede convertir una expresión lambda con una asignación en el cuerpo (incluso si se usa como valor de retorno). Esto puede cambiar con C # 4.0 y .NET 4.0, que permiten que se expresen más en un árbol de expresiones. En otras palabras, con los ejemplos que dio MojoFilter, los dos casi siempre se convertirán en la misma cosa. (Más detalles en un minuto.)

Podemos usar el truco de parámetros delegados si cambiamos un poco los cuerpos un poco:

using System; using System.Linq.Expressions; public class Test { static void Main() { int x = 0; Foo( () => x ); Foo( delegate { return x; } ); } static void Foo(Func<int, int> action) { Console.WriteLine("I suspect the anonymous method..."); } static void Foo(Expression<Func<int>> func) { Console.WriteLine("I suspect the lambda expression..."); } }

¡Pero espera! Podemos diferenciar entre los dos incluso sin usar árboles de expresión, si somos lo suficientemente astutos. El siguiente ejemplo usa las reglas de resolución de sobrecarga (y el truco de combinación de delegados anónimo) ...

using System; using System.Linq.Expressions; public class Base { public void Foo(Action action) { Console.WriteLine("I suspect the lambda expression..."); } } public class Derived : Base { public void Foo(Action<int> action) { Console.WriteLine("I suspect the anonymous method..."); } } class Test { static void Main() { Derived d = new Derived(); int x = 0; d.Foo( () => { x = 0; } ); d.Foo( delegate { x = 0; } ); } }

Ay. Recuerde niños, cada vez que sobrecarga un método heredado de una clase base, un pequeño gatito comienza a llorar.


Respuesta corta: no.

Una respuesta más larga que puede no ser relevante:

  • Si asigna el lambda a un tipo de delegado (como Func o Action ) obtendrá un delegado anónimo.
  • Si asigna el lambda a un tipo de Expresión, obtendrá un árbol de expresiones en lugar de un delegado anónimo. El árbol de expresiones se puede compilar a un delegado anónimo.

Editar: Aquí hay algunos enlaces para Expressions.

  • System.Linq.Expression.Expression(TDelegate) (comienza aquí).
  • Linq in-memory con delegados (como System.Func) usa System.Linq.Enumerable . Linq to SQL (y cualquier otra cosa) con expresiones usa System.Linq.Queryable . Verifique los parámetros en esos métodos.
  • Una explicación de ScottGu . En pocas palabras, Linq in-memory producirá algunos métodos anónimos para resolver su consulta. Linq to SQL producirá un árbol de expresiones que representa la consulta y luego traducirá ese árbol a T-SQL. Linq to Entities producirá un árbol de expresiones que representa la consulta y luego traducirá ese árbol en SQL apropiado para la plataforma.