Pregunta

Leí rápidamente la documentación de Microsoft Lambda Expression .

Este tipo de ejemplo me ha ayudado a comprender mejor:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

Aún así, no entiendo por qué es una innovación. Es solo un método que muere cuando & Quot; variable de método & Quot; termina, ¿verdad? ¿Por qué debería usar esto en lugar de un método real?

¿Fue útil?

Solución

Expresiones de Lambda son una sintaxis más simple para delegados anónimos y se pueden usar en cualquier lugar donde se pueda usar un delegado anónimo. Sin embargo, lo contrario no es cierto; Las expresiones lambda se pueden convertir en árboles de expresión, lo que permite una gran cantidad de magia como LINQ to SQL.

El siguiente es un ejemplo de una expresión LINQ to Objects usando los delegados anónimos y luego las expresiones lambda para mostrar cuánto más fáciles son para el ojo:

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

Las expresiones Lambda y los delegados anónimos tienen una ventaja sobre escribir una función independiente: implementan cierres que puede permitirle pasar el estado local a la función sin agregar parámetros a La función o la creación de objetos de un solo uso.

Los árboles de expresiones son una nueva característica muy poderosa de C # 3.0 que permite que una API vea la estructura de una expresión en lugar de obtener una referencia a un método que se puede ejecutar. Una API solo tiene que convertir un parámetro delegado en un parámetro Expression < T > y el compilador generará un árbol de expresiones desde un lambda en lugar de un delegado anónimo:

void Example(Predicate<int> aDelegate);

llamado como:

Example(x => x > 5);

se convierte en:

void Example(Expression<Predicate<int>> expressionTree);

El último obtendrá una representación del árbol de sintaxis abstracta que describe la expresión x > 5 . LINQ to SQL se basa en este comportamiento para poder convertir las expresiones C # en las expresiones SQL deseadas para el filtrado / pedido / etc. en el lado del servidor.

Otros consejos

Las funciones y expresiones anónimas son útiles para métodos únicos que no se benefician del trabajo adicional requerido para crear un método completo.

Considera este ejemplo:

 string person = people.Find(person => person.Contains("Joe"));

versus

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

Estos son funcionalmente equivalentes.

Los encontré útiles en una situación en la que quería declarar un controlador para el evento de algún control, usando otro control. Para hacerlo normalmente, tendría que almacenar las referencias de los controles en los campos de la clase para poder usarlos en un método diferente al que fueron creados.

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

gracias a las expresiones lambda puedes usarlo así:

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

Mucho más fácil.

Lambda's limpió la sintaxis anónima de delegados de C # 2.0 ... por ejemplo

Strings.Find(s => s == "hello");

Se hizo en C # 2.0 de esta manera:

Strings.Find(delegate(String s) { return s == "hello"; });

Funcionalmente, hacen exactamente lo mismo, es solo una sintaxis mucho más concisa.

Esta es solo una forma de usar una expresión lambda. Puede usar una expresión lambda en cualquier lugar puede usar un delegado. Esto te permite hacer cosas como esta:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

Este código buscará en la lista una entrada que coincida con la palabra " hola " La otra forma de hacer esto es pasar un delegado al método Buscar, como este:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

EDIT :

En C # 2.0, esto podría hacerse usando la sintaxis anónima de delegado:

  strings.Find(delegate(String s) { return s == "hello"; });

Lambda ha mejorado significativamente la sintaxis.

Microsoft nos ha dado una forma más limpia y conveniente de crear delegados anónimos llamados expresiones Lambda. Sin embargo, no se presta mucha atención a la parte de expresiones de esta declaración. Microsoft lanzó un espacio de nombres completo, System.Linq.Expressions , que contiene clases para crear árboles de expresiones basados ??en expresiones lambda. Los árboles de expresión se componen de objetos que representan la lógica. Por ejemplo, x = y + z es una expresión que podría ser parte de un árbol de expresiones en .Net. Considere el siguiente ejemplo (simple):

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

Este ejemplo es trivial. Y estoy seguro de que estás pensando, "esto es inútil, ya que podría haber creado directamente al delegado en lugar de crear una expresión y compilarla en tiempo de ejecución". Y tú estarías bien. Pero esto proporciona la base para los árboles de expresión. Hay una serie de expresiones disponibles en los espacios de nombres de Expresiones, y usted puede crear las suyas propias. Creo que puedes ver que esto podría ser útil cuando no sabes exactamente lo que debería ser el algoritmo en el momento de diseño o compilación. Vi un ejemplo en algún lugar para usar esto para escribir una calculadora científica. También puede usarlo para los sistemas Bayesian , o para programación genética (AI). Algunas veces en mi carrera tuve que escribir una funcionalidad similar a Excel que permitía a los usuarios ingresar expresiones simples (sumas, restas, etc.) para operar con los datos disponibles. En pre- .Net 3.5, tuve que recurrir a algún lenguaje de scripting externo a C #, o tuve que usar la funcionalidad de emisión de código en la reflexión para crear un código .Net sobre la marcha. Ahora usaría árboles de expresión.

Se ahorra tener que tener métodos que solo se usan una vez en un lugar específico para que no se definan lejos del lugar donde se usan. Los buenos usos son como comparadores de algoritmos genéricos como la clasificación, donde puede definir una función de ordenación personalizada donde invoca la ordenación en lugar de alejarse, obligándolo a buscar en otra parte para ver en qué está ordenando.

Y no es realmente una innovación. LISP ha tenido funciones lambda durante aproximadamente 30 años o más.

Una expresión lambda es como un método anónimo escrito en lugar de una instancia delegada.

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

Considera la expresión lambda x = > x * x;

  

El valor del parámetro de entrada es x (en el lado izquierdo de = >)

     

La lógica de la función es x * x (en el lado derecho de = >)

El código de una expresión lambda puede ser un bloque de instrucciones en lugar de una expresión.

x => {return x * x;};

Ejemplo

Nota: Func es un delegado genérico predefinido.

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

Referencias

  1. ¿Cómo puede un delegado y amp; ¿Se puede usar la interfaz de manera intercambiable?

También puede encontrar el uso de las expresiones lambda al escribir códigos genéricos para actuar según sus métodos.

Por ejemplo: función genérica para calcular el tiempo que tarda una llamada de método. (es decir, Action aquí)

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

Y puede llamar al método anterior usando la expresión lambda de la siguiente manera,

var timeTaken = Measure(() => yourMethod(param));

La expresión le permite obtener valor de retorno de su método y también fuera de su parámetro

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));

Muchas veces, solo estás usando la funcionalidad en un solo lugar, por lo que hacer un método es simplemente un alboroto en la clase.

La expresión Lambda es una forma concisa de representar un método anónimo. Tanto los métodos anónimos como las expresiones Lambda le permiten definir la implementación del método en línea, sin embargo, un método anónimo requiere explícitamente que defina los tipos de parámetros y el tipo de retorno para un método. La expresión Lambda usa la característica de inferencia de tipo de C # 3.0 que le permite al compilador inferir el tipo de variable según el contexto. ¡Es muy conveniente porque nos ahorra mucho escribir!

Es una forma de tomar una pequeña operación y colocarla muy cerca de donde se usa (no como una declaración de una variable cerca de su punto de uso). Se supone que esto hace que su código sea más legible. Al anonimizar la expresión, también es mucho más difícil para alguien romper el código de su cliente si la función se usa en otro lugar y se modifica para " mejorar " it.

De manera similar, ¿por qué necesitas usar foreach? Puede hacer todo en foreach con un simple for loop o simplemente usando IEnumerable directamente. Respuesta: no lo necesita , pero hace que su código sea más legible.

La innovación está en el tipo seguridad y transparencia. Aunque no declara tipos de expresiones lambda, se deducen y se pueden usar por búsqueda de código, análisis estático, herramientas de refactorización y reflexión en tiempo de ejecución.

Por ejemplo, antes de que pudieras haber usado SQL y pudieras obtener un ataque de inyección de SQL, porque un hacker pasó una cadena donde normalmente se esperaba un número. Ahora usaría una expresión lambda LINQ, que está protegida de eso.

No es posible crear una API LINQ en delegados puros, ya que requiere combinar árboles de expresiones antes de evaluarlos.

En 2016, la mayoría de los idiomas populares tienen soporte para lambda expression , y C # fue uno de Los pioneros en esta evolución entre los principales lenguajes imperativos.

Esta es quizás la mejor explicación de por qué usar expresiones lambda - > https://youtu.be/j9nj5dTo54Q

En resumen, es para mejorar la legibilidad del código, reducir las posibilidades de errores al reutilizar en lugar de replicar el código, y aprovechar la optimización que se produce entre bastidores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top