expresiones - lambda expressions c#
¿Cuál es el alcance de una variable lambda en C#? (8)
C # no admite el sombreado de esa manera.
La razón por la cual o1
funciona nuevamente es porque no o1
el o1
anterior.
Estoy confundido sobre el alcance de la variable lambda, tome por ejemplo lo siguiente
var query =
from customer in clist
from order in olist
.Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == // line 1
olist.Where(o1 => o1.CustomerID == customer.CustomerID) // line 2
.Max(o1 => o1.OrderDate) // line 3
)
select new {
customer.CustomerID,
customer.Name,
customer.Address,
order.Product,
order.OrderDate
};
En la línea 1, he declarado una variable lambda ''o'', lo que significa que no puedo volver a declararla en la línea 2 (o al menos el compilador se queja si intento) pero no se queja de la línea 3 aunque ''o1'' ya existe ??
¿Cuál es el alcance de una variable lambda?
El alcance de un parámetro lambda es igual al alcance completo del cuerpo de la expresión lambda, incluidas las expresiones o ámbitos internos de lambda.
Si ampliamos la sintaxis de sus expresiones lambda y agregamos alguna sangría amiga, puede volverse más clara (¡aunque probablemente en ninguna parte tan clara como la respuesta diagramática de yamen !):
.Where(o => {
return o.CustomerID == customer.CustomerID
&& o.OrderDate == olist.Where(
o1 => o1.CustomerID == customer.CustomerID
)
.Max(
o1 => o1.OrderDate
);
})
Observe que su .Where().Max()
se encuentra dentro de un .Where()
externo. La o
en la lambda externa está encapsulada por la lambda externa dentro de su lambdas interno (esto se llama cierre ) de modo que ya existe en el alcance de su lambdas interno, y no puede reutilizarse como parámetro.
Puedes reutilizar o1
porque tus dos lambdas internas están completamente separadas una de otra, por lo que no viven más allá del alcance de ninguna de ellas.
Es lo mismo que con cualquier otra variable. El alcance de o
es la expresión completa en su primer Where
, por lo que no puede usarlo nuevamente en el segundo, que está dentro del primero. Pero el alcance de o1
es solo la expresión en su segundo Where
, por lo que puede usarlo en la expresión de su Max
, que está fuera del segundo Where
. En el código:
// o scope lasts until the first bracket is closed
Where(o => o.CustomerID == customer.CustomerID && o.OrderDate ==
// o1 scope lasts until the second bracket is closed; the first is not yet closed here
olist.Where(o1 => o1.CustomerID == customer.CustomerID)
// The second bracket is closed, so o1 is already out of scope; o is still in scope
.Max(o1 => o1.OrderDate)
)
// The first bracket is closed, so o is finally out of scope
Intento imaginarlo así según tu código ...
.Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == // line 1
olist.Where(o1 => o1.CustomerID == customer.CustomerID) // line 2
.Max(o1 => o1.OrderDate) // line 3
)
Una forma bastante tosca de explicar, pero sus corchetes determinan el alcance. Tu segundo o1 no está anidado dentro del segundo, de otra forma tendrías el mismo problema
//outermost where
((BEGIN-o
//inner where
(BEGIN-o1 END-o1)
//max
(BEGIN-o1 END-o1)
END-o))
Los corchetes dan la clave: la variable lambda se captura en el ámbito de su declaración:
.Where(o => ... olist.Where(o1 => ...).Max(o1 => ...))
// |----------------------------------------------| scope of o
// |---------| scope of first o1
// |---------| scope of second o1
Tenga en cuenta que no hay superposición para las dos variables o1
, pero ambas se superponen (o sombrean) la variable o
y, por lo tanto, no pueden usar el mismo nombre.
No puede usar el mismo nombre de variable en dos ámbitos si uno de los ámbitos contiene el otro.
En su pregunta, o
se introduce en el ámbito externo, por lo que no se puede usar nuevamente en el segundo Where()
o en Max()
, porque estos ámbitos están contenidos en el exterior.
Por otro lado, puede usar o1
en ambos ámbitos internos porque uno no contiene el otro, por lo que no hay ambigüedad allí.
porque el lamda es el reemplazo de la función anónima aquí en tu código
Mismo alcance
Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == //line 1
olist.Where(o1 => o1.CustomerID == customer.CustomerID) //line 2
es el alcance de la función en la cual varialble "o" live
aquí, en la línea tres, esta es una nueva pérdida de la variable, es decir, un nuevo alcance funcional
Alcance diferente
.Max(o1 => o1.OrderDate) ) //line 3
entonces el reson en la línea 1 y la línea 2 varialbe "o" definido en la línea 1 no se puede definir en la línea 2 debido a la misma scrop y la definición "o1" en la línea 2 se puede definir nuevamente en la línea 3 porque está en un alcance de función diferente
var external = 1;
//This is a scope
Action scope = new Action(() =>
{
//myVar is not accessible from outside
var myVar = 0 + external;
Console.WriteLine(myVar); //outputs 1
});
//Call the scope
scope();
//Console.WriteLine(myVar);//Will not compile
Cuando se compila el código, toda la lógica del vacío declarado en la acción ()=>{ ... }
moverá a un método en el tipo con un nombre destrozado.
El tiempo de ejecución llamará a la función recién creada cuando llegue a ese lugar en la pila.
Puede pasar valores a un alcance / lambda de varias maneras, que es lo mismo para sacarlos.
Las variables declaradas en una lambda no son accesibles afuera con su nombre declarado.
También es posible utilizar el reflejo para extraer el nombre destrozado, pero no estoy seguro de que lo requiera. (Por favor, avíseme si me equivoco).