Perché questo codice funziona? Sto usando C # 8 con Visual Studio 2019.
Hai risposto alla tua domanda! È perché stai usando C # 8.
La regola da C # 1 a 7 era: un nome semplice non può essere usato per indicare due cose diverse nello stesso ambito locale. (La regola effettiva era leggermente più complessa di quella ma descriveva quanto fosse noiosa; vedi la specifica C # per i dettagli.)
L'intenzione di questa regola era di prevenire il tipo di situazione di cui stai parlando nel tuo esempio, in cui diventa molto facile essere confuso sul significato del locale. In particolare, questa regola è stata progettata per prevenire confusioni come:
class C
{
int x;
void M()
{
x = 123;
if (whatever)
{
int x = 356;
...
E ora abbiamo una situazione in cui all'interno del corpo M
, x
mezzi sia this.x
e locale x
.
Sebbene ben intenzionato, ci sono stati una serie di problemi con questa regola:
- Non è stato implementato secondo le specifiche. Vi erano situazioni in cui un nome semplice poteva essere usato come, ad esempio, sia un tipo che una proprietà, ma questi non venivano sempre contrassegnati come errori perché la logica di rilevamento degli errori era errata. (Vedi sotto)
- I messaggi di errore erano formulati in modo confuso e riportati in modo incoerente. Vi erano più messaggi di errore diversi per questa situazione. Hanno identificato in modo incoerente l'autore del reato; cioè, a volte l' uso interiore sarebbe stato richiamato, a volte l' esterno , e talvolta era solo confuso.
Ho fatto uno sforzo nella riscrittura di Roslyn per risolvere questo problema; Ho aggiunto alcuni nuovi messaggi di errore e reso coerenti quelli precedenti per quanto riguarda la segnalazione dell'errore. Tuttavia, questo sforzo era troppo piccolo, troppo tardi.
Il team di C # ha deciso per C # 8 che l'intera regola stava causando più confusione di quanto impedisse, e la regola è stata ritirata dalla lingua. (Grazie a Jonathon Chase per determinare quando è avvenuta la pensione.)
Se sei interessato a conoscere la storia di questo problema e come ho tentato di risolverlo, vedi questi articoli che ho scritto al riguardo:
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/
Alla fine della terza parte ho notato che c'era anche un'interazione tra questa funzione e la funzione "Colore colore", ovvero la funzione che consente:
class C
{
Color Color { get; set; }
void M()
{
Color = Color.Red;
}
}
Qui abbiamo usato il nome semplice Color
per fare riferimento sia this.Color
al tipo enumerato Color
; secondo una lettura rigorosa della specifica questo dovrebbe essere un errore, ma in questo caso la specifica era errata e l'intenzione era di consentirla, poiché questo codice non è ambiguo e sarebbe irritante far cambiare lo sviluppatore.
Non ho mai scritto quell'articolo descrivendo tutte le strane interazioni tra queste due regole, e sarebbe un po 'inutile farlo ora!
x
parametro di quel metodo viene spostato dall'ambito. Vedi sharplab per un esempio.