Używam języka C # od dłuższego czasu, ale nigdy nie zdawałem sobie sprawy z następujących kwestii:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
Dlaczego więc nie mogę używać wartości „i” poza blokiem for, jeśli nie pozwala mi to zadeklarować zmiennej o tej nazwie?
Pomyślałem, że zmienna iteratora używana przez pętlę for jest ważna tylko w swoim zakresie.
int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Odpowiedzi:
Powodem, dla którego nie możesz definiować zmiennej o tej samej nazwie zarówno w pętli for, jak i poza nią, jest to, że zmienne w zakresie zewnętrznym są prawidłowe w zakresie wewnętrznym. Oznacza to, że gdyby było to dozwolone, w pętli for byłyby dwie zmienne „i”.
Zobacz: Zakresy MSDN
Konkretnie:
i
A także: Deklaracje zmiennych lokalnych (sekcja 8.5.1 specyfikacji C #)
Konkretnie:
(Podkreśl moje.)
Co oznacza, że zakresem
i
wewnętrznej pętli for jest pętla for. Z kolei zasięgi
zewnętrznej pętli for to cała główna metoda plus pętla for. Oznacza to, że miałbyś dwa wystąpieniai
wewnątrz pętli, które są nieprawidłowe zgodnie z powyższym.Powodem, dla którego nie możesz tego zrobić,
int A = i;
jest to, żeint i
jest on przeznaczony tylko do użytku wfor
pętli. Dlatego nie jest już dostępny pozafor
pętlą.Jak widać, obie te kwestie są wynikiem określania zakresu; pierwsza kwestia (
int i = 4;
) spowodowałaby powstanie dwóchi
zmiennych w zakresiefor
pętli. Natomiastint A = i;
skutkowałoby dostępem do zmiennej, która jest poza zakresem.Zamiast tego można zadeklarować
i
zakres dla całej metody, a następnie użyć go zarówno w metodzie, jak i w zakresie pętli for. Pozwoli to uniknąć złamania którejkolwiek zasady.EDYCJA :
Kompilator C # można oczywiście zmienić, aby umożliwić poprawną kompilację tego kodu. W końcu to jest ważne:
Ale czy naprawdę korzystne byłoby dla czytelności i łatwości utrzymania kodu, gdybyśmy mogli pisać taki kod, jak:
Pomyśl o potencjale błędów tutaj, czy ostatni
i
wydruk wyświetla 0 lub 4? To bardzo mały przykład, który jest dość łatwy do naśladowania i śledzenia, ale jest zdecydowanie mniej łatwy w utrzymaniu i czytelności niż zadeklarowanie zewnętrzneji
pod inną nazwą.Uwaga:
Należy pamiętać, że reguły zakresu C # różnią się od reguł określania zakresu C ++ . W C ++ zmienne znajdują się tylko w zakresie od miejsca ich zadeklarowania do końca bloku. Co uczyniłoby twój kod prawidłową konstrukcją w C ++.
źródło
i
zmiennej wewnętrznej ; wydaje mi się to bardziej oczywiste.i
definicja została przeniesiona przed pętlą for, wewnętrznai
definicja zostanie oznaczona jako nieprawidłowa.Odpowiedź J.Kommera jest poprawna: w skrócie, niedozwolone jest deklarowanie zmiennej lokalnej w lokalnej przestrzeni deklaracji zmiennej, która nakłada się na inną lokalną przestrzeń deklaracji zmiennej, która ma zmienną lokalną o tej samej nazwie.
Istnieje również dodatkowa reguła języka C #, która jest tutaj naruszona. Dodatkową zasadą jest to, że użycie prostej nazwy w odniesieniu do dwóch różnych jednostek w dwóch różnych nakładających się przestrzeniach deklaracji lokalnych zmiennych jest niedozwolone. Więc twój przykład jest nie tylko nielegalny, ale także nielegalny:
Ponieważ teraz prosta nazwa „x” została użyta wewnątrz lokalnej przestrzeni deklaracji zmiennej „y”, aby oznaczać dwie różne rzeczy - „this.x” i lokalny „x”.
Więcej analiz tych problemów można znaleźć pod adresem http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ .
źródło
int y = this.x;
this.x
nie jest prostą nazwą .Istnieje sposób zadeklarowania i użycia
i
wewnątrz metody po pętli:Możesz to zrobić w Javie (może pochodzić z C, nie jestem pewien). Jest to oczywiście trochę bałaganiarskie ze względu na nazwę zmiennej.
źródło
Jeśli zadeklarowałeś
i
przed swoimfor
pętlą, czy uważasz, że powinno być nadal ważne, aby zadeklarować ją wewnątrz pętli?Nie, ponieważ wtedy zakres tych dwóch pokrywałby się.
Jeśli chodzi o niemożność zrobienia
int A=i;
, to po prostu dlatego, żei
istnieje tylko wfor
pętli, tak jak powinno.źródło
Oprócz odpowiedzi J.Kommera (+1 btw). Jest to w standardzie dla zakresu NET:
W związku z tym wartość int i zdekalowana w nagłówku pętli for będzie w zakresie tylko podczas bloku pętli for, ALE jej okres istnienia trwa do zakończenia
Main()
kodu.źródło
Najłatwiej o tym pomyśleć, przenosząc zewnętrzną deklarację I powyżej pętli. Wtedy powinno to stać się oczywiste.
Tak czy inaczej jest to ten sam zakres, dlatego nie można tego zrobić.
źródło
Również reguły języka C # są często niepotrzebne, jeśli chodzi o ścisłe programowanie, ale są po to, aby Twój kod był czysty i czytelny.
na przykład mogli to zrobić tak, że jeśli zdefiniujesz to po pętli, to jest w porządku, jednak ktoś, kto czyta twój kod i przegapił linię definicji, może pomyśleć, że ma to związek ze zmienną pętli.
źródło
Odpowiedź Kommera jest technicznie poprawna. Pozwólcie, że sparafrazuję to żywą metaforą ślepego ekranu.
Między blokiem for a otaczającym blokiem zewnętrznym znajduje się ekran ślepy w jedną stronę, tak że kod z wewnątrz bloku for może zobaczyć kod zewnętrzny, ale kod w bloku zewnętrznym nie może zobaczyć kodu wewnątrz.
Ponieważ kod zewnętrzny nie widzi wewnątrz, nie może używać niczego zadeklarowanego wewnątrz. Ale ponieważ kod w bloku for może widzieć zarówno wewnątrz, jak i na zewnątrz, zmienna zadeklarowana w obu miejscach nie może być jednoznacznie używana przez nazwę.
Więc albo tego nie widzisz, albo C #!
źródło
Spójrz na to w taki sam sposób, jakbyś mógł zadeklarować an
int
wusing
bloku:Jednak ponieważ
int
nie wdrażaIDisposable
, nie można tego zrobić. Może pomóc komuś wyobrazić sobie, jak plikint
zmienna jest umieszczana w zakresie prywatnym.Innym sposobem byłoby stwierdzenie,
Mam nadzieję, że pomoże to w wizualizacji tego, co się dzieje.
Bardzo podoba mi się ta funkcja, ponieważ zadeklarowanie
int
od wewnątrzfor
pętli sprawia, że kod jest ładny i napięty.źródło
using
jest całkiem w porządku, chociaż semantyka jest raczej inna (być może dlatego został odrzucony). Zauważ, żeif (true)
jest to zbędne. Usuń go i masz blok zakresu.