J'ai récemment écrit du code où j'ai involontairement réutilisé un nom de variable comme paramètre d'une action déclarée dans une fonction qui a déjà une variable du même nom. Par exemple:
var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };
Lorsque j'ai repéré la duplication, j'ai été surpris de voir que le code était compilé et fonctionnait parfaitement, ce qui n'est pas un comportement que j'attendrais en fonction de ce que je sais de la portée en C #. Googling rapide relevai SO questions qui se plaignent que le code similaire ne génère une erreur, comme Scope Lambda clarification . (J'ai collé cet exemple de code dans mon IDE pour voir s'il fonctionnerait, juste pour être sûr; il fonctionne parfaitement.) De plus, lorsque j'entre dans la boîte de dialogue Renommer dans Visual Studio, le premier x
est mis en surbrillance en tant que conflit de nom.
Pourquoi ce code fonctionne-t-il? J'utilise C # 8 avec Visual Studio 2019.
x
paramètre entier de cette méthode est déplacé hors de la portée. Voir sharplab pour un exemple.Réponses:
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:
Et maintenant, nous avons une situation où à l'intérieur du corps de
M
,x
signifie à la foisthis.x
et le localx
.Bien que bien intentionnée, cette règle posait un certain nombre de problèmes:
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:
Ici, nous avons utilisé le nom simple
Color
pour faire référence à la foisthis.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!
la source