Вопрос по linq, .net, c# – область видимости локальной переменной в анонимном методе linq (закрытие)

5

Какова область действия локальной переменной, объявленной в Linq Query.

Я писал следующий код

<code>   static void Evaluate()
    {
        var listNumbers = Enumerable.Range(1, 10).Select(i => i);
        int i = 10;
    }
</code>

Компилятор отметил ошибку в строке int i = 10, заявив

<code>A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'child' scope to denote something else 
</code>

Я не могу понять, почему эта ошибка приходит.

Я понимаю, чтоi выйдет из области видимости после первой строки (в цикле foreach). Такi может быть объявлено снова.

Фактическое поведение таково, чтоi недоступен после первой строки (в цикле foreach), что правильно. Ноi не может быть объявлено снова. Это кажется странным.

РЕДАКТИРОВАТЬ Это следующий вопрос, основанный на ответе Андраса. Ответ очень хороший, но вызывает дополнительные сомнения.

<code>  static void Evaluate3()
    {
        var listNumbers = Enumerable.Range(1, 10).Select(i => i);
        var listNumbers1 = Enumerable.Range(1, 10).Select(i => i);
    }
</code>

Основываясь на логике функции Оцените, что .Select (i => i) и int i = 10, оба i, локальны для функционального блока и, следовательно, являются ошибкой усложнения.

Функция Evaluate3 не должна компилироваться, так как в блоке метода есть два i, но она успешно компилируется без предупреждения / ошибки.

Вопрос: Либо как Evaluate, так и Evaluate3 не должны компилироваться, или оба должны компилироваться.

Вы уверены, что это проблема с оператором linq? Если вы переделаете это как.Select(x => x) ошибка действительно уходит? Grant
эта проблема не связана с LINQ. это связано с лямда-выражением внутри linq. .Select (x = & gt; x) - & gt; да ошибка уходит Tilak
возможный дубликатWhat is the scope of a lambda variable in C#? nawfal
Мы широко используем linq, и я никогда не сталкивался с этим. Пробовал и да, я получаю ту же жалобу. Что я считаю более странным, так это то, что я могу иметьvar listNumbers = Enumerable.Range(1, 10).Select(i => i); var listNumbers2 = listNumbers.Cast<string>().Select(i => i); и это не выдает ошибку, даже если я использую одно и то же имя переменной, один раз как целое число и один раз как строку. Похоже, второе использованиеi должно вызвать ошибку тоже ... Grant

Ваш Ответ

2   ответа
7

int i;

... вступает в силу во всей области охвата отstart to finish - не только с той точки, в которой это объявлено. В .Net объявление локальной переменной - это просто инструкция для компилятора зарезервировать это имя и local для всей области видимости. Это означает, что как только он объявлен, он уже зарезервирован для всех строк.before and after.

По сути, это означает, что вы должны прочитатьEvaluate как:

static void Evaluate()  
{  
  int i;  
  var listNumbers = Enumerable.Range(1, 10).Select(i => i);  
  i = 10;
} 

И если вы напишите свой метод соответствующим образом, вы увидите, что вместо этого в лямбда-объявлении возникает ошибка компилятора, что вполне разумно. К счастью, компилятор C # достаточно умен, с человеческой точки зрения, чтобы признать, что упорядочение кода важно дляusи он фактически назначает ошибку компилятора любой исходной строке, которая является вторым или последующим объявлением; отсюда почему в твоей версииEvaluate это происходит на линииint i = 10;, С этим знанием фактического времени жизни функции locali, компилятор правильный: использованиеi тамwill конфликт с более ранним использованиемi в лямбде.

Вы можете использовать явную область видимости, чтобы избежать этого:

static void Evaluate()  
{
  var listNumbers = Enumerable.Range(1, 10).Select(i => i);
  {
    int i = 10;
  }
}

В случаеEvaluate3 Вы просто отметили, что хотя обе лямбды совместно используют область родительских функций, они также имеют свои собственные, и там ихiОни объявлены, и именно поэтому они не мешают друг другу (по сути, они являются областями одного уровня).

между прочимEvaluate а такжеEvaluate3 в конечном итоге можно упростить до этого:

static void Evaluate()
{
  { 
    int i;
  }
  int i; //<-- error
}

static void Evaluate3()
{
   { 
     int i;
   }
   { 
     int i;
   }
   //fine here - both i's are in different scopes.
}

И это фактически второй сценарий, в котором я ранее использовал явную область видимости, то есть в разных областях внутри одной и той же функции, гдеi на самом деле имеет разные типы в каждом. Как я уже сказал, я никогда не делал этого снова, и данный код больше не работает :)

Error: User Rate Limit ExceededisError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Tilak
Error: User Rate Limit Exceeded Tilak
Error: User Rate Limit Exceeded Tilak
1

спецификация:

The scope of a local variable declared in a local-variable-declaration is the block in which the declaration occurs. It is an error to refer to a local variable in a textual position that precedes the local-variable-declarator of the local variable.

Твоя лямбдаi => i находится в области действия локальной переменнойint i = 10 даже если это объявлено заранее. Вместо того, чтобы выдавать ошибку, потому что вы используетеi перед объявлением компилятор указывает, что вы уже использовалиi ссылаться на что-то еще, и что это заявление изменит это.

РЕДАКТИРОВАТЬ: после вашего обновления:

В первом случае ваш первыйi заключен в лямбду, но ваш второйi охватывает всеEvaluate методincluding the lambda - следовательно, вы получаете ошибку.

Во втором случае ваш первыйi заключен в его лямбда, и ваш второйi заключен вits лямбда - ниi находится в рамках другого, поэтому нет ошибки.

Ваш абзац & quot; Основан на логике ... обоих i, локально для функционального блока ... & quot; неверно - первыйi не локально для функционального блока, а для лямбды.

Error: User Rate Limit ExceedediError: User Rate Limit ExceededSelectError: User Rate Limit ExceededSelectError: User Rate Limit ExceededEvaluate()Error: User Rate Limit Exceeded
Error: User Rate Limit ExceedediError: User Rate Limit ExceededSelectError: User Rate Limit ExceedediError: User Rate Limit ExceededEvaluate()Error: User Rate Limit Exceeded

Похожие вопросы