2010-04-22 5 views
12
for (int i = 0; i < 10; i++) 
{ 
    Foo(); 
} 
int i = 10; // error, 'i' already exists 

----------------------------------------  

for (int i = 0; i < 10; i++) 
{ 
    Foo(); 
} 
i = 10; // error, 'i' doesn't exist 

범위에 대한 나의 이해에 따라 첫 번째 예제는 잘되어야합니다. 사실 둘 다 허용되지 않는 것이 훨씬 더 이상해 보입니다. 분명히 '나는'범위에 있거나 그렇지 않습니다.명세서 블록의 변수 범위

범위에 대해 명확하지 않은 부분이 있습니까? 컴파일러가 진정으로 해결할 수 없다는 것을 이해하지 못합니까? 아니면 보모 국가 컴파일러의 사례일까요?

+0

오히려 안전 벨트 법과 비슷합니다. 당신이없는 자동차를 운전할 수없는 기술적 인 이유는 없지만, 매우 불쾌한 충돌로부터 당신을 구할 수 있기 때문에 법을 지키는 것이 좋습니다. –

답변

16

, 첫 번째 예는 잘해야한다.

범위에 대한 이해가 좋습니다. 이것은 범위 지정 오류가 아닙니다. 이것은 단순한 이름 오류의 일관성없는 사용입니다.

int i = 10; // 이미 존재하는 오류입니다.

이는보고 된 오류가 아닙니다.입니다. 보고 된 오류는 "이 범위 내에서 으로 선언 할 수 없습니다. 자식 범위에서 이미 다른 문자를 나타 내기 위해 사용 된 i와 다른 의미를 갖기 때문에"

오류 메시지는입니다. 오류가 무엇인지 알려줍니다. 오류 메시지를 다시 읽으십시오. 선언 사이에 갈등이 있다고는 말할 수 없습니다. 간단한 이름의 의미가 변경되므로 오류는 입니다. 오류는 이 아니며 재 선언입니다. 두 개의 서로 다른 범위에 동일한 이름을 가진 두 가지를 포함하는 것이 합법적입니다. 심지어 그러한 범위가 중첩되는 경우에도 마찬가지입니다. 이 아니라면은 하나의 간단한 이름을 의미합니다. 중첩 된 지역 변수 선언의 공백은 두 가지입니다..

오류 대신 당신이

int i = 10; 
int i = 10; 

분명히 '내가'범위에 여부 중 하나입니다

같은 것을 한 경우에 "나는 이미이 범위에 정의라는 이름의 지역 변수를"얻을 것입니다.

물론 이죠? 주어진 i가 범위 내에 있는지의 여부는 부적합합니다. 예 :

class C 
{ 
    int i; 
    void M() 
    { 
     string i; 

완벽하게 합법적입니다. 외부 i는 M을 통해 범위 내에 있습니다. 외부 범위를 음영 처리하는 로컬 i를 선언해도 아무런 문제가 없습니다. 루프 변수 및 필드 - 당신은 지금 당신이 두 개의 중첩 지역 변수 선언 공간에 다른 두 가지 의미로 난을 사용했기 때문에

class C 
{ 
    int i; 
    void M() 
    { 
     int x = i; 
     foreach(char i in ... 

을했다하면 어떻게 문제가 될 것 같습니다. 이는 혼란스럽고 오류가 발생하기 쉽기 때문에 불법입니다.

컴파일러가 진정으로 해결할 수없는 범위에 대해 명확하지 않은 부분이 있습니까?

나는 그 질문을 이해하지 못한다. 분명히 컴파일러 은 프로그램을 완전히 분석 할 수있는입니다. 컴파일러가 각각의 사용법의 의미를 해석하지 못하면 어떻게 오류 메시지를보고 할 수 있습니까? 컴파일러는 'i'를 사용하여 동일한 로컬 변수 선언 공간에서 서로 다른 두 가지를 의미하는 것으로 완전히 판단 할 수 있으며 그에 따라 오류를보고합니다.

0

유모 상태 컴파일러주의의 경우입니까?

정확히 그. 동일한 메소드에서 변수 이름을 "재사용"하는 것은 의미가 없습니다. 이것은 단지 오류의 원인 일 뿐이며 더 이상은 아닙니다.

+0

문제는 변수 이름을 재사용하는 것이 아닙니다. 하나의 메소드에서 변수 이름을 여러 번 재사용하는 것이 합법적입니다. 특정 로컬 변수 선언 공간 내에서 * 두 개의 다른 것들을 참조하기 위해 동일한 * 간단한 이름 *을 사용하는 것은 합법적이지 않습니다. –

1

첫 번째 예에서 루프 외부의 i 선언은 i를 함수의 지역 변수로 만듭니다. 결과적으로, 그 함수의 블록 내에서 선언 된 다른 변수 이름을 갖는 것은 오류입니다.

둘째, 나는 루프 중에 만 범위 내에 있습니다. 루프 외부에서는 더 이상 액세스 할 수 없습니다.

그래서 당신은 오류를 보았다,하지만 난의 범위가 각 블록 내에서 제한되어 있기 때문에이

for (int i = 0; i < 10; i++) 
{ 
    // do something 
} 

foreach (Foo foo in foos) 
{ 
    int i = 42; 
    // do something 
} 

을하고 아무 문제가 없다.

9

선언 공간이 메서드 수준에서 i을 정의하기 때문입니다. 변수 i은 루프의 끝 부분에서 범위를 벗어났습니다. i이 이미 해당 메서드에 정의 되었기 때문에 여전히 i을 다시 선언 할 수 없습니다. 선언 우주 대

범위 : 당신은 (기본적으로 누구 항상 옳다 다음과 같은 질문에 관한) 에릭 Lippert의의 대답에서 살펴 봐야 할 것입니다

http://csharpfeeds.com/post/11730/Whats_The_Difference_Part_Two_Scope_vs_Declaration_Space_vs_Lifetime.aspx

. 그것에

봐 이런 식으로 : 여기

http://blogs.msdn.com/ericlippert/archive/2009/08/03/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx

나는 그들이 왜 그렇게했는지에 대해 이야기를 생각 위에서 언급 한 게시물에 에릭의 코멘트입니다. 항상 변수의 선언을 소스 코드의 변수로 옮기려면 같은 블록에 그대로 두어야합니다. 우리가 당신의 방식대로했을 경우 가끔은 법적이고 때때로 불법 일 것입니다! 그러나 우리가 정말로 피하고 싶은 것은 C++에서 어떤 일이 일어나는가? C++에서는 변수를 옮기는 경우 가 실제로 다른 간단한 이름의 바인딩을 바꾼다!

+1

그런데 왜 같은 방법으로 다른 루프의 범위에서'i'를 정의 할 수 있습니까? 나는 아직도 그것이 컴파일러 측의 관료주의라고 생각한다. –

+1

@ 마이클 : 루프가 형제 범위이기 때문에 그렇게 할 수 있습니다. 형제 범위에서 동일하게 명명 된 변수를 정의하는 충돌은 서로의 범위를 벗어났기 때문에 충돌이 없습니다. –

+0

@Zach : 그러나 원래 질문의 첫 번째 블록은 정확히 다음을 보여줍니다. 충돌이 없습니다. 그러나 여전히 컴파일되지는 않습니다. – Foxfire

0

저 컴파일러가 ifor 루프 이내 범위 메소드 수준 &에서 선언 된 말을 의미 생각합니다.

따라서, 사례 1 - 당신이 경우 2

&을 수행하는 변수가 이미 존재한다는 오류를 얻을 - 변수가 for 루프 내에서만 범위이기 때문에, 그 루프 외부에서 액세스 할 수 없습니다

이 발생하지 않도록하려면 수 :

var i = 0; 

for(i = 0, i < 10, i++){ 
} 

i = 10; 

하지만이 작업을 수행 할 것입니다 경우 생각할 수 없다.

0

HTH 당신은

  int i ; 
      for (i = 0; i < 10; i++) 
      { 

      } 
      i = 10; 
+3

그건 사악한 코드입니다. – Foxfire

1

참으로 내가 두 번째 "유모 상태 compilerism"설명을 할 필요가있다. 흥미로운 점은 이것이 괜찮다는 것입니다.

for (int i = 0; i < 10; i++) 
{ 

} 

for (int i = 0; i < 10; i++) 
{ 

} 

이 확인

for (int i = 0; i < 10; i++) 
{ 

} 

for (int j = 0; j < 10; j++) 
{ 
    var i = 12;     
} 

이지만 그것은 모든 조금 일관성의이

for (int i = 0; i < 10; i++) 
{ 
    var k = 12; 
} 

for (int i = 0; i < 10; i++) 
{ 
    var k = 13; 
} 

을 할 수 있지만이

for (int i = 0; i < 10; i++) 
{ 
    var x = 2; 
} 

var x = 5; 

도 없습니다. 아래의 에릭과의 의견 교환을 바탕으로

편집, 내가 루프를 처리하려고 어떻게 보여 도움이 될 줄 알았는데. 가능할 때마다 루프를 자체 메서드로 작성하려고합니다. 가독성을 높이기 때문에이 작업을 수행합니다.

BEFORE

/* 
* doing two different things with the same name is unclear 
*/ 
for (var index = 0; index < people.Count; index++) 
{ 
    people[index].Email = null; 
} 
var index = GetIndexForSomethingElse(); 

AFTER 가입일

/* 
* Now there is only one meaning for index in this scope 
*/ 
ClearEmailAddressesFor(people); // the method name works like a comment now 
var index = GetIndexForSomethingElse(); 

/* 
* Now index has a single meaning in the scope of this method. 
*/ 
private void ClearEmailAddressesFor(IList<Person> people) 
{ 
    for (var index = 0; index < people.Count; index++) 
    { 
     people[index].Email = null; 
    } 
} 

+1

일치하지 않습니다. 가장 단순한 이름이 직접적으로 사용되는 가장 바깥 쪽의 지역 변수 선언 공간을 통해 동일한 간단한 이름을 사용하여 다른 두 가지를 나타낼 수 없다는 규칙이 있습니다 *. for 루프는 지역 변수 선언 공간을 정의합니다. 이 규칙은 각 예제에서 일관되게 적용된다는 것을 알게 될 것입니다. –

+0

사양의 언어를 구문 분석 할 때 일관성이있을 수 있지만 소비자의 관점에서는 일관성이 없습니다. 변수가 범위를 벗어나서 사용할 수 없다면 동일한 이름의 다른 변수를 만들 수 없어야한다는 데는 이유가 없습니다. –

+0

* 매우 좋은 이유가 * 있습니다. 아주 간단한 이유는 동일한 간단한 이름을 사용하여 선언 공간을 겹치게하는 두 개의 다른 엔티티를 참조하는 것이 혼란스럽고 * 버그가 발생하기 쉽고 따라서 * 불법 *이어야하기 때문입니다. –

5

C# spec on local variable declarations :

로컬 변수의 범위는 로컬 변수 선언에서 선언 선언이 발생한 블록입니다.

지금은 물론, 당신은 선언 전에 i를 사용할 수 있지만, i 선언의 범위는 포함 전체 블록 :

{ 
    // scope starts here 
    for (int i = 0; i < 10; i++) 
    { 
     Foo(); 
    } 
    int i = 10; 
} 

fori 변수 하위 범위에 있으므로 변수 이름이 충돌합니다.우리는 선언의 위치를 ​​재 배열 할 경우

는 충돌이 명확하게 :

범위 내 이해함으로써
{ 
    int i = 10; 

    // collision with i 
    for (int i = 0; i < 10; i++) 
    { 
     Foo(); 
    } 
} 
+0

그게 정말 명확한 그림 잭, 감사합니다. – fearofawhackplanet

0
class Test 
{ 
    int i; 
    static int si=9; 

    public Test() 
    { 
     i = 199; 
    } 

    static void main() 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      var x = 2; 
     } 

     { var x = 3; } 

     { // remove outer "{ }" will generate compile error 
      int si = 3; int i = 0; 

      Console.WriteLine(si); 
      Console.WriteLine(Test.si); 
      Console.WriteLine(i); 
      Console.WriteLine((new Test()).i); 
     } 
    } 
}