Какова область лямбда-переменной в С#?
Я запутался в области лямбда-переменной, возьму, например, следующие
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
};
В строке 1 я объявляю лямбда-переменную 'o', что означает, что я не могу объявить ее снова в строке 2 (или, по крайней мере, компилятор жалуется, если я пытаюсь)
Но он не жалуется на строку 3, хотя "o1" уже существует?
Какова область действия лямбда-переменной?
Ответы
Ответ 1
Скобки дают ключ - переменная лямбда фиксируется в области, где она была объявлена:
.Where(o => ... olist.Where(o1 => ...).Max(o1 => ...))
// |----------------------------------------------| scope of o
// |---------| scope of first o1
// |---------| scope of second o1
Обратите внимание, что нет перекрытия для двух переменных o1
, но они оба перекрывают (или теневую) переменную o
и, следовательно, не могут использовать одно и то же имя.
Ответ 2
Объем параметра лямбда равен всей области тела лямбда-выражения, включая любые внутренние лямбда-выражения или области видимости.
Если мы разложим синтаксис ваших лямбда-выражений и добавим дружественный отступ, он может стать яснее (хотя, вероятно, нигде не ясен как yamen diagrammatic answer!):
.Where(o => {
return o.CustomerID == customer.CustomerID
&& o.OrderDate == olist.Where(
o1 => o1.CustomerID == customer.CustomerID
)
.Max(
o1 => o1.OrderDate
);
})
Обратите внимание, что ваш вызов .Where().Max()
находится внутри внешнего .Where()
. o
во внешней лямбда инкапсулируется внешней лямбдой внутри ваших внутренних лямбдов (это называется замыканием), так что она существует в области ваших внутренних лямбда и уже не может использоваться повторно как параметр.
Вы можете повторно использовать o1
, потому что ваши две внутренние лямбды полностью отделены друг от друга, поэтому он не выходит за рамки одного из них.
Ответ 3
Вы не можете использовать одно и то же имя переменной в двух областях, если одна из областей содержит другую.
В вашем вопросе o
вводится во внешнюю область видимости, поэтому его нельзя использовать снова во втором Where()
или в Max()
, потому что эти области содержатся во внешнем.
С другой стороны, вы можете использовать o1
во внутренних областях, потому что один не содержит другого, поэтому там нет двусмысленности.
Ответ 4
becasue lamda - это замена анонимной функции здесь, в вашем коде
Тот же масштаб
Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == //line 1
olist.Where(o1 => o1.CustomerID == customer.CustomerID) //line 2
- это область функций, в которой varialble "o" live
здесь, в третьей строке, это новый scrop переменной i.e new scope scope
Разная область
.Max(o1 => o1.OrderDate) ) //line 3
так что резонанс в строке1 и строке2 varialbe "o", определенный в строке1, не может быть определен в строке2 из-за того же масштаба, а определение "o1" в строке2 может быть определено снова в строке3, потому что оно находится в разной функциональной области
Ответ 5
С# не поддерживает теневое воспроизведение.
Причина o1
снова работает, заключается в том, что она не теневая предыдущая o1
.
Ответ 6
Это то же самое, что и с любой другой переменной. Объем o
- это целое выражение в вашем первом Where
, поэтому вы не можете использовать его снова во втором, который находится внутри первого. Но область o1
- это просто выражение во втором Where
, поэтому вы можете использовать его в выражении вашего Max
, которое находится за пределами второго Where
. В коде:
// 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
Ответ 7
Я пытаюсь сделать это так, как ваш код...
.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
)
Довольно грубый способ объяснить, но ваши скобки определяют область действия. Ваш второй o1 не вложен внутри второго, где, кроме того, у вас будет такая же проблема.
//outermost where
((BEGIN-o
//inner where
(BEGIN-o1 END-o1)
//max
(BEGIN-o1 END-o1)
END-o))
Ответ 8
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
Когда код скомпилирован, вся логика из void, объявленная в Action ()=>{ ... }
, будет перенесена в метод типа с измененным именем.
Время выполнения вызовет вновь созданную функцию, когда она достигнет этого места в стеке.
Вы можете передавать значения в область/лямбда различными способами, которые одинаковы для их получения.
Переменные, объявленные в лямбда, не доступны снаружи с объявленным им именем.
Также можно использовать отражение, чтобы вытащить искаженное имя, но я не уверен, что вы этого требуете. (Пожалуйста, дайте мне знать, если я ошибаюсь.)