Ce n'est pas tout simplement mal ?
Non, ce n'est pas mal du tout. Il s'agit d'une mise en œuvre correcte de la section 7.5.2.1 de la spécification C#, "Noms simples, significations invariantes dans les blocs".
La spécification indique :
Pour chaque occurrence d'un identifiant donné donné en tant que nom simple dans une ou un déclarateur, dans le espace de déclaration des variables locales de cette occurrence, chaque autre occurrence du même identificateur en tant que nom simple dans une doit faire référence au même entité. Cette règle garantit que la signification d'un nom est toujours la même à l'intérieur d'un bloc donné, d'un bloc de commutation, d'une déclaration for, foreach ou using, ou d'un fonction anonyme.
Pourquoi C# est-il incapable de faire la différence entre les deux scopes ?
La question n'a pas de sens ; il est évident que le compilateur est capable de différencier les deux portées. Si le compilateur n'était pas capable de faire la différence entre les deux champs d'application alors comment l'erreur a-t-elle pu être produite ? Le message d'erreur dit qu'il y a deux champs d'application différents, et donc que les champs d'application ont été différenciés !
Le premier champ d'application de la FI ne devrait-il pas être complètement séparé du reste de la méthode ?
Non, il ne devrait pas. La portée (et l'espace de déclaration des variables locales) définie par l'instruction de bloc à la suite de l'instruction conditionnelle fait lexicalement partie du bloc externe qui définit le corps de la méthode. Par conséquent, les règles relatives au contenu du bloc externe s'appliquent au contenu du bloc interne.
Je ne peux pas appeler var depuis l'extérieur du if, le message d'erreur est donc faux, car le premier var n'a aucune pertinence dans la seconde portée.
C'est complètement faux. Il est spécieux de conclure que, simplement parce que la variable locale n'est plus dans la portée, le bloc externe ne contient pas d'erreur. Le message d'erreur est correct.
L'erreur ici n'a rien à voir avec le fait que la portée d'une variable chevauche la portée d'une autre variable ; la seule chose qui est pertinente ici est que vous avez un bloc - le bloc externe - dans lequel le même nom simple est utilisé pour faire référence à deux choses complètement différentes. C# exige qu'un nom simple ait une seule signification dans le bloc qui l'utilise en premier .
Par exemple :
class C
{
int x;
void M()
{
int x = 123;
}
}
C'est parfaitement légal ; la portée du x extérieur chevauche la portée du x intérieur, mais ce n'est pas une erreur. Ce qui est une erreur est :
class C
{
int x;
void M()
{
Console.WriteLine(x);
if (whatever)
{
int x = 123;
}
}
}
parce que maintenant le simple nom "x" a deux significations différentes dans le corps de M -- il signifie "this.x" et la variable locale "x". Il est déroutant pour les développeurs et les mainteneurs de code que le même nom simple ait deux significations différentes. dans le même bloc donc c'est illégal.
Nous autorisons les blocs parallèles à contenir le même nom simple utilisé de deux manières différentes, ce qui est légal :
class C
{
int x;
void M()
{
if (whatever)
{
Console.WriteLine(x);
}
if (somethingelse)
{
int x = 123;
}
}
}
car maintenant le seul bloc qui contient deux utilisations incohérentes de x est le bloc externe, et ce bloc n'est pas directement ne contiennent aucun usage de "x", seulement indirectement .