Recientemente escribí un código en el que involuntariamente reutilicé un nombre de variable como parámetro de una acción declarada dentro de una función que ya tiene una variable del mismo nombre. Por ejemplo:
var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };
Cuando descubrí la duplicación, me sorprendió ver que el código se compilaba y se ejecutaba perfectamente, lo cual no es un comportamiento que esperaría según lo que sé sobre el alcance en C #. Algunos rápida búsqueda en Google se presentó lo que las preguntas que se quejan de que un código similar no producir un error, como Lambda Ámbito Aclaración . (Pegué ese código de muestra en mi IDE para ver si se ejecutaría, solo para asegurarme; funciona perfectamente.) Además, cuando entro en el cuadro de diálogo Cambiar nombre en Visual Studio, el primero x
se resalta como un conflicto de nombres.
¿Por qué funciona este código? Estoy usando C # 8 con Visual Studio 2019.
x
parámetro de ese método se mueve fuera del alcance. Ver sharplab para un ejemplo.Respuestas:
¡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:
Y ahora tenemos una situación en la que dentro del cuerpo de
M
,x
significa ambosthis.x
y lo localx
.Aunque bien intencionado, hubo una serie de problemas con esta regla:
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:
Aquí hemos usado el nombre simple
Color
para referirnos a ambosthis.Color
y al tipo enumeradoColor
; 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!
fuente