2008-11-17 12 views
22

Poniższy kod nie kompiluje stwierdzenia "Zmienna lokalna o nazwie" st "nie może być zadeklarowana w tym zakresie, ponieważ nadałaby ona inne znaczenie" st ", która jest już używana w zakresie" potomnym " na oznaczenie czegoś innego „:Child Scope & CS0136

 var l = new List<string>(); 
     l.Find(st => st.EndsWith("12")); 
     string st = "why this fails?"; 

rozumiem dlaczego to nie będzie działać:

 string preParent = ""; 
     { 
      string preParent = "Should fail cause we change the meaning"; 
     } 

Kiedy mamy następujące dostajemy” CS0103: nazwa «postParent» nie istnieje w bieżącym kontekst ":

 { 
      string postParent=string.Empty; 
     } 
     postParent = "Should this work?"; 

Czego nie rozumiem, to dlaczego kompilator jest wystarczająco inteligentny, aby zobaczyć, że postParent nie jest w zasięgu, ale nie pozwala mi zdefiniować nowej zmiennej, która ma taką samą nazwę, jak zmienna używana w zasięgu podrzędnym (co oczywiście jest poza zakresem).

Czy prosty zakres zastosowania kompilatora jest wymuszany przez odmowę zezwolenia na użycie zmiennej? Jeśli tak, to ma sens.

===========

Zmieniano:

myślę, co ja również znaleźć interesujące jest to, w jaki sposób można mieć tej samej zmiennej w dwóch zakresach dzieci w jednej metody, tak to jest ważne:

 { 
      string thisWorks= string.Empty; 
     } 
     { 
      string thisWorks= "Should this work?"; 
     } 

Jestem po prostu trochę dziwne, że można mieć dwie zmienne o tej samej nazwie, o ile są one na tym samym poziomie (jeśli spojrzeć na zakres postaci drzewa). Ma to sens, ponieważ możesz mieć zmienne lokalne w dwóch metodach tej samej klasy o tej samej nazwie.

Jestem zaskoczony, że kompilator jest w stanie odróżnić i zezwolić na to, podczas gdy nie pozwoli na to zmienna postParent. Czy to jest techniczne ograniczenie, czy też była to decyzja projektowa? To właśnie próbuję dostać ;-)

+2

Dlaczego spadek po 5 miesiącach? – JoshBerke

Odpowiedz

12

Tak, kompilator wymusza zakres. Zauważ, że zakres zmiennej jest blokiem leksykalnym, którego jest częścią - nie tylko od momentu deklaracji, ale także całego zakresu.

Kompilator narzeka, ponieważ przypisanie do postParent wykracza poza zakres (który jest tylko zagnieżdżonymi nawiasami klamrowymi). Jeśli próbujesz zadeklarować nową zmienną w punkcie, w którym aktualnie przypisujesz numer postParent, problem dotyczył zagnieżdżonego bloku, ponieważ zakres postParent obejmowałby ten zagnieżdżony blok, mimo że był przed deklaracją.

Zakresy opisano w sekcji 3.7 specyfikacji C# 3.0.

EDYCJA: Aby odpowiedzieć na edycję pytania.

To tylko dwie proste zasady:

  • nie można zadeklarować zmienną lokalną, gdy inna zmienna lokalna o tej samej nazwie znajduje się w zakresie
  • zakresu zmiennej lokalnej jest blok, w którym deklaracja występuje:

Jestem pewien, że język mógł zostać zaprojektowany w taki sposób, że zakres zaczynał się dopiero w momencie deklaracji, ale uważam, że prostsze (pod względem złożoności językowej) jest rozważenie zakresów jako samych bloków - tak wszystkie zmienne lokalne zadeklarowane w ten sam blok ma taki sam zakres, na przykład. To sprawia, że ​​życie jest o wiele prostsze, gdy rozważamy przechwycone zmienne - ponieważ to, co zostanie przechwycone, zależy od zakresu, a zagnieżdżone zakresy sprawiają, że życie staje się interesujące ...

EDYCJA: Specyfikacja języka ma to do powiedzenia na temat oryginalnego przykładu wyrażenia lambda - to rozdział 7.14.1:

opcjonalny anonimowa funkcja-podpis anonimowej funkcji definiuje nazwy i ewentualnie rodzaje formalnych parametrów dla funkcji anonimowej. Zakres parametrów anonimowej funkcji to anonimowy korpus funkcji anonimowej. Wraz z listą parametrów (jeśli jest podana), jednostka anonimowego-metody stanowi przestrzeń deklaracji . Z tego powodu, to jest błąd czasu kompilacji dla nazwy parametru anonimowego funkcji, aby dopasować nazwy lokalnego zmiennej, lokalnego stała lub parametr którego zakres obejmuje anonimowy sposobie wyrażania lub wyrażenie lambda.

Czy to pomaga?

+0

Niezależnie od tego, dlaczego właśnie to egzekwuje tę zasadę, nadal uważam, że jest to defekt w CLR. Metody anonimowe powinny definitywnie zinterpretować wszystkie utworzone w nich zmienne z dowolnej innej funkcji, nawet tak proste, jak CLR, dodając przedrostek do każdej zmiennej w metodzie delegatów. –

+2

System CLR nie jest tutaj w ogóle zaangażowany. To decyzja językowa. I całkowicie się nie zgadzam. Chodzi o to, że zmienne zewnętrzne są dostępne dla funkcji anonimowej, więc funkcja anonimowa nie może ich przedefiniować, dokładnie tak samo, jak gdyby zmienna była redeclared w "normalnym" bloku. –

+0

To ma sens, ponieważ zakładając, że deklaracja jest częścią całego bloku zasięgu, nie można się dowiedzieć, czy zmienna zewnętrzna ma zostać przekształcona w funkcję anonimową, czy też nie. Jeśli opierałoby się na tym, gdzie zmienna była określona na podstawie zakresu, można na to pozwolić. – JoshBerke

-2

Deklarujesz zmienną w ograniczonym zakresie i próbujesz jej użyć poza tym zakresem. Kompilator zakłada, że ​​nie chcesz mieć do niego dostępu, aby można było zadeklarować zmienną o tej samej nazwie gdzie indziej w pliku. Twoja próba zrobienia starego triku C zakładającego, że zmienna będzie żyła bezpośrednio poza zakresem. Na przykład to działało w starszych wersjach C/C++, ale już go nie ma.

for (int i=0; i<10; i++) 
{ 
    cout <<”In the loop i is “<< i << endl; 
} 
cout << “outside of the loop i is “ << i << endl; //this only compiles with old C/C++ compilers. 
+2

Jared nie jest tym, co starałem się zrobić ;-) C# nie pozwala ci zadeklarować zmiennej o tej samej nazwie, jeśli ta zmienna jest zadeklarowane w ramach zakresu podrzędnego. – JoshBerke