¿Por qué funciona este código? Estoy usando C # 8 con Visual Studio 2019.
¡Has respondido tu propia pregunta! Es porque estás usando C # 8.
La regla de C # 1 a 7 fue: un nombre simple no puede usarse para significar dos cosas diferentes en el mismo ámbito local. (La regla real era un poco más compleja que eso, pero describía cómo es tedioso; consulte la especificación de C # para más detalles).
La intención de esta regla era evitar el tipo de situación de la que está hablando en su ejemplo, donde resulta muy fácil confundirse sobre el significado de lo local. En particular, esta regla fue diseñada para evitar confusiones como:
class C
{
int x;
void M()
{
x = 123;
if (whatever)
{
int x = 356;
...
Y ahora tenemos una situación en la que dentro del cuerpo de M
, x
significa ambos this.x
y lo local x
.
Aunque bien intencionado, hubo una serie de problemas con esta regla:
- No se implementó según las especificaciones. Hubo situaciones en las que se podía usar un nombre simple como, por ejemplo, un tipo y una propiedad, pero no siempre se marcaron como errores porque la lógica de detección de errores era defectuosa. (Vea abajo)
- Los mensajes de error fueron redactados de manera confusa e informados de manera inconsistente. Hubo múltiples mensajes de error diferentes para esta situación. Inconsistentemente identificaron al delincuente; es decir, a veces se llamaba el uso interno , a veces el externo , y a veces era simplemente confuso.
Hice un esfuerzo en la reescritura de Roslyn para resolver esto; Agregué algunos mensajes de error nuevos e hice que los viejos fueran consistentes con respecto a dónde se informó el error. Sin embargo, este esfuerzo fue muy poco, demasiado tarde.
El equipo de C # decidió para C # 8 que toda la regla estaba causando más confusión de la que impedía, y la regla se retiró del lenguaje. (Gracias Jonathon Chase por determinar cuándo ocurrió la jubilación).
Si está interesado en conocer la historia de este problema y cómo intenté solucionarlo, vea estos artículos que escribí al respecto:
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/
Al final de la tercera parte, noté que también había una interacción entre esta función y la función "Color Color", es decir, la función que permite:
class C
{
Color Color { get; set; }
void M()
{
Color = Color.Red;
}
}
Aquí hemos usado el nombre simple Color
para referirnos a ambos this.Color
y al tipo enumerado Color
; de acuerdo con una lectura estricta de la especificación, esto debería ser un error, pero en este caso la especificación era incorrecta y la intención era permitirla, ya que este código no es ambiguo y sería molesto hacer que el desarrollador lo cambie.
Nunca escribí ese artículo describiendo todas las extrañas interacciones entre estas dos reglas, ¡y sería un poco inútil hacerlo ahora!
x
parámetro de ese método se mueve fuera del alcance. Ver sharplab para un ejemplo.