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

Уточнение области лямбда

Почему мой параметр x ведет себя так хаотично?

  • Пример 1 - не существует в текущем контексте.
  • Пример 2 - Нельзя повторно использовать x, потому что он определен в области "child".
  • Пример 3 - Хорошо. Это та часть, в которой я смущен. Возможно, различная "детская" область?

Пример 1:

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var result = list.Where(x => x < 3);
Console.Write(result.ElementAt(x));

создает эту ошибку времени компиляции:

В текущем контексте имя 'x' не существует

который я ожидаю.

Пример 2:

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var result = list.Where(x => x < 3);
int x = 1;
Console.Write(result.ElementAt(x));

создает эту ошибку времени компиляции:

Локальная переменная с именем 'x' не может быть объявлена ​​в этой области, поскольку она означало бы другое значение "х", которое уже используется в 'child' для обозначения чего-то еще

Насколько я понял, в этом вопросе я понял, Есть ли причина повторного использования С# переменной в foreach?. Однако этого я никогда не видел. Кроме того, он дает ответы на этот вопрос, Какова область видимости лямбда-переменной в С#?, неполная или неправильная.

Пример 3:

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
List<string> stringList = new List<string> { "A", "B" };
var result = list.Where(x => x < 3);
var result2 = stringList.Where(x => x != "A");

Console.Write(result2);

Произошла ошибка.


С принятым ответом эти сообщения в блоге от Эрика Липперта помогли мне обернуть голову вокруг того, что происходит. Если кто-то все еще запутался:

пространство объявлений

простые имена

4b9b3361

Ответ 1

В Example 1 x определяется в локальной области выражения lamdba и не отображается в третьей строке

В Example 2 теперь вы объявили две переменные с именем "x" в той же области объявления (видимость отличается)

С помощью метода лямбда или анонимности он "захватывает" область, в которой он запущен. Если у вас есть локальный x в той же области, что и определение лямбда, тогда он "фиксирует" это x, чтобы втянуть в то, что лямбда может получить доступ, что приводит к двум определениям "x". То, что вы объявляете в лямбде, не захватывается в другом направлении, поэтому оно не видно за пределами лямбда.

В Example 3 Теперь вы не используете переменную, которая является локальной только лямбда вне лямбда, и не называя что-то одно и то же в той же области объявления.

Ответ 2

Области ребенка (пример 3) могут использовать одни и те же переменные, но родительский и дочерний языки не могут повторно объявлять переменные.

Вы можете получить то же самое для:

// Child scopes
for (int i = 1; i < 10; i++){ /* do something */ }
for (int i = 1; i < 10; i++){ /* do something else */ }

Это не получится:

// Child and parent
for (int i = 1; i < 10; i++){ /* do something */ }
int i = 33;

Ответ 3

Это не так сложно, как кажется.

Если вы определяете параметр для выражения lamda, этот параметр действителен только в области выражения lamda

(int x) =>
{
   //x is only valid inside this scope
}

Если у вас есть вторая переменная с определенной в той же области действия, что и выражение lamda, вы получите ошибку, потому что эта вторая переменная также действительна в области выражения lamda.

void Foo()
{

 int y;

 //y is valis in the scope of foo

 (int x) =>
 {
    //x is only valid inside this scope
    //y is valid in the scope of foo and the lamda expression
 }
}

В третьем примере у вас есть 2 разных выражения lamda и, следовательно, две разные области