Escrevi recentemente algum código em que reutilizei involuntariamente um nome de variável como parâmetro de uma ação declarada em uma função que já possui uma variável com o mesmo nome. Por exemplo:
var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };
Quando vi a duplicação, fiquei surpreso ao ver que o código compilava e executava perfeitamente, o que não é um comportamento que eu esperaria com base no que sei sobre o escopo em C #. Uma rápida Googling transformou-se tão perguntas que se queixam de que um código semelhante se produzir um erro, como o Lambda Âmbito Esclarecimento . (Colei esse código de exemplo no meu IDE para ver se ele seria executado, apenas para garantir; ele funciona perfeitamente.) Além disso, quando eu insiro a caixa de diálogo Renomear no Visual Studio, o primeiro x
é destacado como um conflito de nome.
Por que esse código funciona? Estou usando o C # 8 com o Visual Studio 2019.
x
parâmetro desse método é movido para fora do escopo. Veja sharplab para um exemplo.Respostas:
Você respondeu sua própria pergunta! É porque você está usando C # 8.
A regra de C # 1 a 7 era: um nome simples não pode ser usado para significar duas coisas diferentes no mesmo escopo local. (A regra real era um pouco mais complexa que essa, mas descreve como é tedioso; consulte a especificação do C # para obter detalhes.)
A intenção dessa regra era impedir o tipo de situação que você está falando no seu exemplo, onde fica muito fácil confundir o significado do local. Em particular, essa regra foi projetada para evitar confusões como:
E agora temos uma situação em que, dentro do corpo de
M
,x
significa ambosthis.x
e o localx
.Embora bem-intencionado, houve vários problemas com essa regra:
Fiz um esforço na reescrita de Roslyn para resolver isso; Eu adicionei algumas novas mensagens de erro e tornei as antigas consistentes em relação a onde o erro foi relatado. No entanto, esse esforço foi muito pouco, muito tarde.
A equipe do C # decidiu para o C # 8 que toda a regra estava causando mais confusão do que impedia, e a regra foi retirada do idioma. (Obrigado Jonathon Chase por determinar quando a aposentadoria aconteceu.)
Se você estiver interessado em aprender o histórico desse problema e como tentei corrigi-lo, consulte estes artigos que escrevi sobre ele:
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/
No final da parte três, observei que havia também uma interação entre esse recurso e o recurso "Color Color" - ou seja, o recurso que permite:
Aqui usamos o nome simples
Color
para se referir a ambosthis.Color
e ao tipo enumeradoColor
; de acordo com uma leitura estrita da especificação, isso deve ser um erro, mas, neste caso, a especificação estava errada e a intenção era permiti-la, pois esse código é inequívoco e seria irritante fazer o desenvolvedor alterá-lo.Eu nunca escrevi esse artigo descrevendo todas as interações estranhas entre essas duas regras, e seria um pouco inútil fazê-lo agora!
fonte