Подтвердить что ты не робот

Какова область лямбда-переменной в С#?

Я запутался в области лямбда-переменной, возьму, например, следующие

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" уже существует?

Какова область действия лямбда-переменной?

4b9b3361

Ответ 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 ()=>{ ... }, будет перенесена в метод типа с измененным именем.

Время выполнения вызовет вновь созданную функцию, когда она достигнет этого места в стеке.

Вы можете передавать значения в область/лямбда различными способами, которые одинаковы для их получения.

Переменные, объявленные в лямбда, не доступны снаружи с объявленным им именем.

Также можно использовать отражение, чтобы вытащить искаженное имя, но я не уверен, что вы этого требуете. (Пожалуйста, дайте мне знать, если я ошибаюсь.)