Buscar..


Observaciones

Cierres

Las expresiones Lambda capturarán implícitamente las variables utilizadas y crearán un cierre . Un cierre es una función junto con algún contexto de estado. El compilador generará un cierre cada vez que una expresión lambda "encierre" un valor de su contexto circundante.

Ej. Cuando se ejecuta lo siguiente

Func<object, bool> safeApplyFiltererPredicate = o => (o != null) && filterer.Predicate(i);

safeApplyFilterPredicate se refiere a un nuevo objeto creado que tiene una referencia privado al valor actual de filterer , y cuya Invoke método comporta como

o => (o != null) && filterer.Predicate(i);

Esto puede ser importante, ya que mientras se mantenga la referencia al valor ahora en safeApplyFilterPredicate , habrá una referencia al objeto al que se refiere actualmente el filterer . Esto tiene un efecto en la recolección de basura y puede causar un comportamiento inesperado si el objeto al que se refiere el filterer actualidad está mutado.

Por otro lado, los cierres se pueden usar para deliberar un efecto para encapsular un comportamiento que involucra referencias a otros objetos.

P.ej

var logger = new Logger();
Func<int, int> Add1AndLog = i => {
    logger.Log("adding 1 to " + i);
    return (i + 1);
};

Los cierres también se pueden utilizar para modelar máquinas de estado:

Func<int, int> MyAddingMachine() {
    var i = 0;
    return x => i += x;
};

Expresiones lambda basicas

Func<int, int> add1 = i => i + 1;

Func<int, int, int> add = (i, j) => i + j;

// Behaviourally equivalent to:

int Add1(int i)
{
    return i + 1;
}

int Add(int i, int j)
{
    return i + j;
}

...

Console.WriteLine(add1(42)); //43
Console.WriteLine(Add1(42)); //43
Console.WriteLine(add(100, 250)); //350
Console.WriteLine(Add(100, 250)); //350

Expresiones lambda básicas con LINQ

// assume source is {0, 1, 2, ..., 10}

var evens = source.Where(n => n%2 == 0);
// evens = {0, 2, 4, ... 10}

var strings = source.Select(n => n.ToString());
// strings = {"0", "1", ..., "10"}

Usando la sintaxis lambda para crear un cierre

Ver comentarios para la discusión de los cierres. Supongamos que tenemos una interfaz:

public interface IMachine<TState, TInput>
{
    TState State { get; }
    public void Input(TInput input);
}

y luego se ejecuta lo siguiente:

IMachine<int, int> machine = ...;
Func<int, int> machineClosure = i => {
    machine.Input(i);
    return machine.State;
};

Ahora machineClosure refiere a una función de int a int , que detrás de escena usa la instancia de IMachine que se refiere la machine para llevar a cabo el cálculo. Incluso si la machine referencia queda fuera del alcance, siempre que se machineClosure objeto machineClosure , la instancia original de IMachine se mantendrá como parte de un 'cierre', definido automáticamente por el compilador.

Advertencia: esto puede significar que la misma llamada de función devuelve valores diferentes en momentos diferentes (por ejemplo, en este ejemplo si la máquina mantiene una suma de sus entradas). En muchos casos, esto puede ser inesperado y debe evitarse para cualquier código en un estilo funcional: los cierres accidentales e inesperados pueden ser una fuente de errores.

Sintaxis Lambda con cuerpo de bloque de declaración

Func<int, string> doubleThenAddElevenThenQuote = i => {
    var doubled = 2 * i;
    var addedEleven = 11 + doubled;
    return $"'{addedEleven}'";
};

Expresiones Lambda con System.Linq.Expressions

Expression<Func<int, bool>> checkEvenExpression = i => i%2 == 0;
// lambda expression is automatically converted to an Expression<Func<int, bool>>


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow