Dlaczego ten kod działa? Używam C # 8 z Visual Studio 2019.
Odpowiedziałeś na swoje pytanie! To dlatego, że używasz C # 8.
Reguła od C # 1 do 7 brzmiała: prosta nazwa nie może oznaczać dwóch różnych rzeczy w tym samym zasięgu lokalnym. (Rzeczywista reguła była nieco bardziej skomplikowana, ale opisywała, jak to jest nużące; szczegółowe informacje można znaleźć w specyfikacji C #).
Celem tej reguły było zapobieżenie sytuacji, o której mówisz w swoim przykładzie, w której bardzo łatwo jest pomylić się co do znaczenia tego, co lokalne. W szczególności zasada ta została zaprojektowana w celu zapobiegania nieporozumieniom, takim jak:
class C
{
int x;
void M()
{
x = 123;
if (whatever)
{
int x = 356;
...
A teraz mamy sytuację, w której wnętrze ciała oznacza zarówno lokalne M
, x
jak this.x
i lokalne x
.
Mimo dobrych intencji z tą regułą było wiele problemów:
- Nie został zaimplementowany zgodnie ze specyfikacją. Zdarzały się sytuacje, w których można było użyć prostej nazwy jako, powiedzmy, zarówno typu, jak i właściwości, ale nie zawsze były one oznaczane jako błędy, ponieważ logika wykrywania błędów była wadliwa. (Patrz poniżej)
- Komunikaty o błędach były myląco sformułowane i niespójnie zgłaszane. W tej sytuacji było wiele różnych komunikatów o błędach. Niespójnie zidentyfikowali sprawcę; to znaczy, czasami wewnętrzne użycie byłoby odwołane, czasami zewnętrzne , a czasami było to po prostu mylące.
W przepisie Roslyn starałem się to rozwiązać; Dodałem kilka nowych komunikatów o błędach i sprawiłem, że stare były spójne pod względem miejsca zgłoszenia błędu. Jednak wysiłek ten był zbyt mały, zbyt późny.
Zespół C # zdecydował dla C # 8, że cała reguła powoduje więcej zamieszania niż zapobiega, i reguła została wycofana z języka. (Dzięki Jonathon Chase za ustalenie, kiedy nastąpiła emerytura.)
Jeśli chcesz poznać historię tego problemu i sposób, w jaki próbowałem go naprawić, zapoznaj się z artykułami, które o nim napisałem:
https://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/
https://ericlippert.com/2009/11/05/simple-names-are-not-so-simple-part-two/
https://ericlippert.com/2014/09/25/confusing-errors-for-a-confusing-feature-part-one/
https://ericlippert.com/2014/09/29/confusing-errors-for-a-confusing-feature-part-two/
https://ericlippert.com/2014/10/03/confusing-errors-for-a-confusing-feature-part-three/
Pod koniec trzeciej części zauważyłem, że istnieje także interakcja między tą funkcją a funkcją „Kolor koloru” - to znaczy funkcją, która pozwala:
class C
{
Color Color { get; set; }
void M()
{
Color = Color.Red;
}
}
W tym przypadku użyliśmy prostej nazwy Color
w odniesieniu zarówno do, jak this.Color
i do wyliczonego typu Color
; według ścisłego odczytania specyfikacji powinien to być błąd, ale w tym przypadku specyfikacja była niepoprawna, a intencją było zezwolenie na to, ponieważ kod ten jest jednoznaczny i denerwujące byłoby zmuszenie dewelopera do jego zmiany.
Nigdy nie napisałem tego artykułu opisującego wszystkie dziwne interakcje między tymi dwiema regułami, i byłoby to teraz bezcelowe!
x
parametr tej metody zostaje usunięty z zakresu. Zobacz na przykład sharplab .