Uso o C # há bastante tempo, mas nunca percebi o seguinte:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
Então, por que não posso usar o valor de 'i' fora do bloco for se ele não me permite declarar uma variável com esse nome?
Eu pensei que a variável iteradora usada por um loop for é válida apenas em seu escopo.
int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Respostas:
O motivo pelo qual você não pode definir uma variável com o mesmo nome no loop for e fora do loop for é porque as variáveis no escopo externo são válidas no escopo interno. Significando que haveria duas variáveis 'i' dentro do loop for, se isso fosse permitido.
Consulte: Escopos do MSDN
Especificamente:
e
E também: Declarações de variáveis locais (Seção 8.5.1 da especificação C #)
Especificamente:
(Ênfase minha.)
O que significa que o escopo do
i
interior do loop for é o loop for. Considerando que o escopo da partei
externa do loop for é todo o método principal mais o loop for. Ou seja, você teria duas ocorrênciasi
dentro do loop que são inválidas de acordo com o acima.A razão pela qual você não pode fazer isso
int A = i;
é porque oint i
escopo é apenas para uso dentro dofor
loop. Portanto, não é mais acessível fora dofor
loop.Como você pode ver, esses dois problemas são resultado do escopo; o primeiro problema (
int i = 4;
) resultaria em duasi
variáveis nofor
escopo do loop. Considerandoint A = i;
que resultaria no acesso a uma variável que está fora do escopo.Em vez disso, o que você pode fazer é declarar o
i
escopo definido para todo o método e usá-lo no método e no escopo do loop for. Isso evitará violar qualquer regra.EDIT :
Obviamente, o compilador C # pode ser alterado para permitir que esse código seja compilado com bastante validade. Depois de tudo isso é válido:
Mas seria realmente benéfico para a legibilidade e a manutenção do código poder escrever código como:
Pense no potencial de erros aqui, o último
i
imprime 0 ou 4? Agora, este é um exemplo muito pequeno, fácil de seguir e rastrear, mas é definitivamente muito menos sustentável e legível do que ter declarado o exteriori
com um nome diferente.NB:
Observe que as regras de escopo do C # diferem das regras de escopo do C ++ . Em C ++, as variáveis estão apenas no escopo de onde são declaradas até o final do bloco. O que tornaria seu código uma construção válida em C ++.
fonte
i
variável embora; isso parece mais óbvio para mim.i
definição externa fosse movida antes do loop for, ai
definição interna seria marcada como inválida.A resposta de J.Kommer está correta: brevemente, é ilegal que uma variável local seja declarada em um espaço de declaração de variável local que se sobreponha a outro espaço de declaração de variável local que tenha um local com o mesmo nome.
Há uma regra adicional de C # que é violada aqui também. A regra adicional é que é ilegal que um nome simples seja usado para se referir a duas entidades diferentes dentro de dois espaços de declaração de variáveis locais sobrepostos diferentes. Portanto, o seu exemplo não é apenas ilegal, mas também é ilegal:
Como agora o nome simples "x" foi usado dentro do espaço de declaração da variável local "y" para significar duas coisas diferentes - "this.x" e o local "x".
Consulte http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ para obter mais análises sobre esses problemas.
fonte
int y = this.x;
this.x
não é um nome simples .Existe uma maneira de declarar e usar
i
dentro do método após o loop:Você pode fazer isso em Java (pode ser originário de C, não tenho certeza). É claro que é um pouco confuso por causa de um nome de variável.
fonte
Se você declarou
i
antes do seufor
loop, você acha que ainda deve ser válido declará-lo dentro do loop?Não, porque o escopo dos dois se sobreporia.
Quanto a não ser capaz de fazer
int A=i;
, bem, isso é simplesmente porquei
só existe nofor
loop, como deveria.fonte
Além da resposta de J.Kommer (+1 btw). Existe isso no escopo padrão do NET:
Portanto, o int i decalarado dentro do cabeçalho do loop for estará no escopo apenas durante o bloco do loop for, MAS a vida útil dura até o
Main()
código ser concluído.fonte
A maneira mais fácil de pensar sobre isso é mover a declaração externa de I para acima do loop. Deve ficar óbvio então.
É o mesmo escopo de qualquer maneira, portanto, não pode ser feito.
fonte
Além disso, as regras do C # muitas vezes não são necessárias em termos de programação estritamente, mas existem para manter seu código limpo e legível.
por exemplo, eles poderiam ter feito isso para que, se você o definir após o loop, tudo bem, mas alguém que lê seu código e perdeu a linha de definição pode pensar que isso tem a ver com a variável do loop.
fonte
A resposta de Kommer é tecnicamente correta. Deixe-me parafrasear com uma vívida metáfora da tela cega.
Existe uma tela cega unidirecional entre o bloco for e o bloco externo anexo, de forma que o código de dentro do bloco for possa ver o código externo, mas o código no bloco externo não pode ver o código dentro.
Como o código externo não pode ver o interior, ele não pode usar nada declarado no interior. Mas como o código no bloco for pode ver dentro e fora, uma variável declarada nos dois lugares não pode ser usada sem ambiguidade pelo nome.
Então, ou você não vê, ou você C #!
fonte
Veja da mesma maneira como se você pudesse declarar um
int
em umusing
bloco:No entanto, como
int
não implementaIDisposable
, isso não pode ser feito. Noint
entanto, pode ajudar alguém a visualizar como uma variável é colocada em um escopo privado.Outra maneira seria dizer,
Espero que isso ajude a visualizar o que está acontecendo.
Eu realmente gosto desse recurso, pois declarar o
int
de dentro dofor
loop mantém o código agradável e rígido.fonte
using
é bastante boa, embora a semântica seja bastante diferente (e talvez por isso foi que o voto foi negativo). Observe queif (true)
é redundante. Remova-o e você terá um bloco de escopo.