Pourquoi ce code fonctionne-t-il? J'utilise C # 8 avec Visual Studio 2019.
Vous avez répondu à votre propre question! C'est parce que vous utilisez C # 8.
La règle de C # 1 à 7 était: un nom simple ne peut pas être utilisé pour signifier deux choses différentes dans la même portée locale. (La règle réelle était légèrement plus complexe que cela, mais décrivant comment cela est fastidieux; voir la spécification C # pour plus de détails.)
L'intention de cette règle était d'empêcher le genre de situation dont vous parlez dans votre exemple, où il devient très facile de se tromper sur le sens du local. En particulier, cette règle a été conçue pour éviter les confusions comme:
class C
{
int x;
void M()
{
x = 123;
if (whatever)
{
int x = 356;
...
Et maintenant, nous avons une situation où à l'intérieur du corps de M
, x
signifie à la fois this.x
et le local x
.
Bien que bien intentionnée, cette règle posait un certain nombre de problèmes:
- Il n'a pas été mis en œuvre conformément aux spécifications. Dans certains cas, un nom simple pouvait être utilisé, par exemple, comme type et comme propriété, mais ceux-ci n'étaient pas toujours signalés comme des erreurs car la logique de détection des erreurs était défectueuse. (Voir ci-dessous)
- Les messages d'erreur étaient formulés de manière confuse et rapportés de manière incohérente. Il y avait plusieurs messages d'erreur différents pour cette situation. Ils ont identifié le contrevenant de façon incohérente; c'est-à-dire que parfois l' usage intérieur était appelé, parfois l' extérieur , et parfois c'était juste déroutant.
J'ai fait un effort dans la réécriture de Roslyn pour régler ce problème; J'ai ajouté de nouveaux messages d'erreur et rendu les anciens cohérents quant à l'endroit où l'erreur a été signalée. Cependant, cet effort était trop peu, trop tard.
L'équipe C # a décidé pour C # 8 que toute la règle causait plus de confusion qu'elle n'en empêchait, et la règle a été retirée du langage. (Merci Jonathon Chase d'avoir déterminé quand la retraite a eu lieu.)
Si vous êtes intéressé à connaître l'historique de ce problème et comment j'ai essayé de le résoudre, consultez les articles que j'ai écrits à ce sujet:
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/
À la fin de la troisième partie, j'ai noté qu'il y avait également une interaction entre cette fonctionnalité et la fonctionnalité "Couleur couleur" - c'est-à-dire la fonctionnalité qui permet:
class C
{
Color Color { get; set; }
void M()
{
Color = Color.Red;
}
}
Ici, nous avons utilisé le nom simple Color
pour faire référence à la fois this.Color
au type énuméré Color
; selon une lecture stricte de la spécification, cela devrait être une erreur, mais dans ce cas, la spécification était erronée et l'intention était de l'autoriser, car ce code est sans ambiguïté et il serait vexant de faire changer le développeur.
Je n'ai jamais écrit cet article décrivant toutes les interactions étranges entre ces deux règles, et il serait un peu inutile de le faire maintenant!
x
paramètre entier de cette méthode est déplacé hors de la portée. Voir sharplab pour un exemple.