[c#] delegar palabra clave vs. notación lambda



Answers

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.

Question

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

delegate { x = 0; }

y

() => { x = 0 }

?




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




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. 



Links