Por que um nome de variável duplicada não pode ser declarado em um escopo local nested?

Com base nesta questão recente, não entendo a resposta fornecida. Parece que você deveria ser capaz de fazer algo assim, já que seus escopos não se sobrepõem

static void Main() { { int i; } int i; } 

Este código não consegue compilar com o seguinte erro:

Uma variável local chamada ‘i’ não pode ser declarada neste escopo porque daria um significado diferente para ‘i’, que já é usado em um escopo ‘filho’ para denotar outra coisa

Eu não acho que nenhuma das respostas até agora tenha conseguido a linha crucial da especificação.

Da seção 8.5.1:

O escopo de uma variável local declarada em uma declaração de variável local é o bloco no qual a declaração ocorre . É um erro referir-se a uma variável local em uma posição textual que precede o declarator de variável local da variável local. Dentro do escopo de uma variável local, é um erro em tempo de compilation declarar outra variável ou constante local com o mesmo nome.

(Ênfase minha)

Em outras palavras, o escopo da variável “posterior” inclui a parte do bloco antes da declaração – isto é, inclui o bloco “interno” que contém a variável “anterior”.

Você não pode se referir à variável mais recente em um lugar anterior à sua declaração – mas ela ainda está no escopo.

“O escopo da variável local ou constante se estende até o final do bloco atual. Você não pode declarar outra variável local com o mesmo nome no bloco atual ou em quaisquer blocos nesteds.” C # 3.0 em poucas palavras, http://www.amazon.com/3-0-Nutshell-Desktop-Reference-OReilly/dp/0596527578/

“O espaço de declaração de variável local de um bloco inclui quaisquer blocos nesteds. Assim, dentro de um bloco nested, não é possível declarar uma variável local com o mesmo nome de uma variável local em um bloco delimitador.” Escopos variables, MSDN, http://msdn.microsoft.com/pt-br/library/aa691107%28v=vs.71%29.aspx

Em uma nota lateral, isso é exatamente o oposto das regras de escopo JavaScript e F #.

Da especificação do idioma C #:

O espaço de declaração de variável local de um bloco inclui quaisquer blocos nesteds. Assim, dentro de um bloco nested, não é possível declarar uma variável local com o mesmo nome de uma variável local em um bloco delimitador.

Essencialmente, não é permitido porque, em C #, seus escopos realmente se sobrepõem.

edit: Só para esclarecer, o escopo do C # é resolvido no nível do bloco, não linha por linha. Então, embora seja verdade que você não pode se referir a uma variável no código que vem antes de sua declaração, também é verdade que seu escopo se estende até o início do bloco.

Esta tem sido uma regra em C # da primeira versão.

Permitir escopos sobrepostos levaria apenas a confusão (dos programadores, não do compilador).

Por isso, foi proibido de propósito.

Não é uma questão de escopos sobrepostos. Em C #, um nome simples não pode significar mais de uma coisa dentro de um bloco onde é declarado. No seu exemplo, o nome i significa duas coisas diferentes dentro do mesmo bloco externo.

Em outras palavras, você deve ser capaz de mover uma declaração de variável para qualquer lugar dentro do bloco em que ela foi declarada sem causar escopos. Desde mudar o seu exemplo para:

 static void Main() { int i; { int i; } } 

faria com que os escopos das diferentes variables i se sobreponham, seu exemplo é ilegal.

Para C #, ISO 23270 ( Tecnologia da Informação – Linguagens de Programação – C # ), §10.3 ( Declarações ) diz:

Cada bloco , switch-block , for-statement , foreach-statement ou using-statement cria um espaço de declaração para variables ​​locais e constantes locais chamado de espaço de declaração de variável local . Os nomes são introduzidos nesse espaço de declaração por meio de declarações de variável local e declarações de constante local .

Se um bloco é o corpo de uma declaração de construtor, método ou operador de instância ou um acessador get ou set para uma declaração de indexador, os parâmetros declarados em tal declaração são membros do espaço de declaração de variável local do bloco.

Se um bloco é o corpo de um método genérico, os parâmetros de tipo declarados em tal declaração são membros do espaço de declaração de variável local do bloco.

É um erro para dois membros de um espaço de declaração de variável local ter o mesmo nome. É um erro para um espaço de declaração de variável local e um espaço de declaração de variável local aninhada para conter elementos com o mesmo nome.

[ Nota: Assim, dentro de um bloco nested, não é possível declarar uma variável ou constante local com o mesmo nome de uma variável ou constante local em um bloco delimitador. É possível que dois blocos nesteds contenham elementos com o mesmo nome, desde que nenhum deles contenha o outro. nota final ]

assim

 public void foobar() { if ( foo() ) { int i = 0 ; ... } if ( bar() ) { int i = 0 ; ... } return ; } 

é legal, mas

 public void foobar() { int i = 0 ; if ( foo() ) { int i = 0 ; ... } ... return ; } 

não é legal. Pessoalmente, acho a restrição bastante irritante. Posso ver a emissão de um aviso do compilador sobre a sobreposição de escopo, mas um erro de compilation? Muito cinto e suspensórios, IMHO. Eu pude ver a virtude de uma opção de compilador e / ou pragma, embora (talvez -pedantic / -practical , #pragma pedantic vs #pragma practical , B^) ).

Eu apenas compilei isso no GCC como C e C ++. Não recebi nenhuma mensagem de erro, por isso parece ser uma syntax válida.

Sua pergunta é marcada como .net e como c. Isso deve ser marcado como c #? Essa linguagem pode ter regras diferentes de C.

Em C você precisa colocar todas as declarações de variables ​​no início de um bloco. Eles precisam vir todos diretamente após a abertura { antes de qualquer outra declaração neste bloco.

Então, o que você pode fazer para compilar é isto:

 static void Main() { { int i; } { int i; } } 

Aqui está sua resposta da documentação do MSDN .NET :

… O espaço de declaração de variável local de um bloco inclui quaisquer blocos nesteds. Assim, dentro de um bloco nested, não é possível declarar uma variável local com o mesmo nome de uma variável local em um bloco delimitador.