Уточнение области лямбда
Почему мой параметр 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);
Произошла ошибка.
С принятым ответом эти сообщения в блоге от Эрика Липперта помогли мне обернуть голову вокруг того, что происходит. Если кто-то все еще запутался:
пространство объявлений
простые имена
Ответы
Ответ 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 и, следовательно, две разные области