6

Linq Query で宣言されたローカル変数のスコープは何ですか。

私は次のコードを書いていました

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

コンパイラは行 int i=10 にエラーをフラグ付けし、次のように述べています

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 

このエラーが発生する理由を理解できません。

私の理解では、i最初の行の後で( foreach ループで)範囲外になります。したがってi、再度宣言することができます。

実際の動作は、i最初の行の後 (foreach ループ内) にはアクセスできませんが、これは正しいことです。しかし、i再度宣言することはできません。これは奇妙に思えます。

編集これは、Andras の回答に基づく次の質問です。答えは非常に良いですが、さらに疑問が生じます。

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

関数のロジックに基づいて .Select(i=>i) と int i=10 を評価し、両方の i が関数ブロックに対してローカルであるため、複雑なエラーが発生します。

関数 Evaluate3 は、メソッド ブロックに i が 2 つあるためコンパイルできませんが、警告やエラーなしで正常にコンパイルされています。

質問、Evaluate と Evaluate3 の両方をコンパイルしないか、両方をコンパイルする必要があります。

4

2 に答える 2

8

ここで注目すべき重要な事実は、次の宣言です。

int i;

...宣言された時点からだけでなく、囲んでいるスコープ全体で最初から最後まで有効になります。.Net では、ローカル変数の宣言は、スコープ全体でその名前とローカルを予約するようコンパイラに指示するだけです。つまり、宣言されると、 の前後のすべての行に対してすでに予約されています。

実際には、実際には次のように読む必要があることを意味しますEvaluate

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

それに応じてメソッドを作成すると、代わりにラムダ宣言でコンパイラ エラーが発生することがわかります。これは完全に合理的です。ありがたいことに、C# コンパイラは、人間の観点からすると、コードの順序が重要であることを認識するほど賢く、実際には、2 番目以降の宣言であるソース行にコンパイラ エラーを割り当てます。したがって、なぜあなたのバージョンではEvaluateそれが行で起こるのですかint i = 10;。関数の local の実際の有効期間に関するこの知識があればi、コンパイラは正しいです。ithereの使用は、ラムダでの以前の使用競合します。i

これを回避するには、明示的なスコープを使用できます。

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

あなたの場合Evaluate3、両方のラムダが親関数のスコープを共有している間、それらも独自のものを持っていることに注意してください。それらiの s が宣言されているのはそこにあります-それが、それらが互いに干渉しない理由です(実際には、兄弟スコープ)。

ちなみにEvaluateEvaluate3最終的には次のように簡略化できます。

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

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

そして、実際には、以前に明示的なスコープを使用した 2 番目のシナリオです。つまり、同じ関数内の異なるスコープで、i実際にはそれぞれに異なる型があります。私が言うように-私は二度とそれをやったことがなく、問題のコードはもうライブではありません:)

于 2012-05-09T14:43:44.787 に答える
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はラムダで囲まれていますが、2番目のケースではラムダを含むメソッドi全体が含まれているため、エラーが発生します。Evaluate

2番目のケースでは、最初のケースiはラムダ内に囲まれ、2番目のケースはラムダ内i囲まれています。どちらももう一方のスコープ内にないため、エラーは発生しません。i

「...両方のiのロジックに基づいて、関数ブロックにローカルです...」という段落は正しくありません。最初の段落は関数ブロックiではなくラムダにローカルです。

于 2012-05-09T14:29:20.960 に答える