web-dev-qa-db-fra.com

L'utilisation de noms de paramètres qui diffèrent des noms de type uniquement par la casse est-elle considérée comme une mauvaise pratique en C #?

Je vois des questions similaires à cela en ce qui concerne les noms de paramètres qui correspondent aux propriétés de la classe, mais je ne trouve rien concernant l'utilisation d'un nom de paramètre identique au nom du type de paramètre, à l'exception de la casse en C #. Cela ne semble pas être une violation que je peux trouver, mais est-ce considéré comme une mauvaise pratique? Par exemple, j'ai la méthode suivante

public Range PadRange(Range range) {}

Cette méthode prend une plage et renvoie une nouvelle plage à laquelle un remplissage a été appliqué. Donc, étant donné le contexte générique, je ne peux pas penser à un nom plus descriptif pour le paramètre. Cependant, je me souviens d'un conseil que j'ai pris lors de la lecture du code complet sur la "distance psychologique". Ça dit

La distance psychologique peut être définie comme la facilité avec laquelle deux éléments peuvent être différenciés ... Pendant que vous déboguez, soyez prêt pour les problèmes causés par une distance psychologique insuffisante entre des noms de variables similaires et entre des noms de routine similaires. Lorsque vous construisez du code, choisissez des noms avec de grandes différences afin d'éviter le problème.

Ma signature de méthode a beaucoup de "Range" en cours, il semble donc que cela puisse être un problème en ce qui concerne cette distance psychologique. Maintenant, je vois de nombreux développeurs faire ce qui suit

public Range PadRange(Range myRange) {}

Personnellement, j'ai un profond dégoût pour cette convention. L'ajout d'un préfixe "my" aux noms de variables ne fournit aucun contexte supplémentaire.

Je vois aussi ce qui suit

public Range PadRange(Range rangeToPad) {}

J'aime mieux cela que le préfixe "mon", mais je m'en fiche toujours. Cela me semble trop verbeux et se lit maladroitement comme un nom de variable. Pour moi, il est entendu que la plage sera complétée en raison du nom de la méthode.

Donc, avec tout cela, mon instinct est d'aller avec la première signature. Pour moi, c'est propre. Pas besoin de forcer le contexte quand il n'est pas nécessaire. Mais est-ce que je fais du tort à moi-même ou aux futurs développeurs avec cette convention? Suis-je en train de violer une bonne pratique?

43
Jason Tyler

Ne pensez pas trop à ça, Range range c'est bien. J'utilise ce type de dénomination depuis plus de 15 ans en C #, et probablement beaucoup plus longtemps en C++, et je n'en ai jamais connu de réels inconvénients, bien au contraire.

Bien sûr, lorsque vous avez différentes variables locales dans la même portée, toutes du même type, cela aidera probablement à investir un certain effort mental pour les distinguer correctement.

100
Doc Brown

Je fais ça tout le temps, ça me donne une grande tranquillité d'esprit. S'il s'agit d'un argument passé à un constructeur qui doit être attribué à un membre, mon membre serait également nommé plage et l'affectation serait

this.range = range;

Et j'aurais généralement une propriété nommée Range.

Ils sont tous la même chose, ne différant que dans leur contexte, il est donc logique de conserver un seul nom et vous devrez vous souvenir d'un seul nom. C'est une chose, les différences sont purement techniques.

Vous devez être strict avec les membres pleinement qualifiés avec "ceci". mais c'est à cela que sert StyleCop.

note latérale StyleCop

Polémique garantie!

À ceux qui préconisent l'utilisation de "ceci": j'ai vu _, m, m_ et rien du tout. Le langage lui-même nous offre une manière parfaitement claire et sans ambiguïté universellement reconnaissable d'indiquer que nous avons affaire à un membre de la classe. Pourquoi diable voudriez-vous créer votre propre chemin qui mutile des noms déjà parfaits?

La seule raison pour laquelle je peux y penser est que c'est une habitude héritée de l'ère C, alors qu'il était en fait logique de le faire parce qu'il n'y avait pas d'autre moyen.

"C'est plus de personnages!" Sérieusement? "Le temps de compilation va monter en flèche!" Sérieusement? "Je devrai lever mon petit doigt lors de la frappe!". Comme si le temps de frappe avait une signification dans le temps de développement total.

Je reconnais que tout style différent de celui auquel vous êtes habitué suscitera une certaine opposition. Mais il est difficile de discuter de cette utilisation de manière cohérente. Voici comment cela fonctionne pour moi: Avant de pousser un nouveau fichier de code, j'exécute StyleCop et il trouvera un certain nombre de membres dépourvus des qualificatifs "this". Je mets "ça". sur le presse-papiers, géré par les membres et insérez. Aucun effort.

StyleCop fait beaucoup plus que cela (haha). Il y a tellement de façons dont un développeur peut (uniquement en considérant la mise en forme du code) frustrer le travail de maintenance de son successeur. StyleCop en empêche la plupart. C'est inestimable.

Si vous êtes nouveau dans ce domaine: cela vous fait généralement vous plaindre pendant une semaine ou deux, puis vous allez l'adorer.

17
Martin Maat

Mon auto-guidage sur les méthodes de nommage, les paramètres et les variables est assez simple:

  1. Si le nom contient le type transmis ou renvoyé, vous vous trompez.
  2. Nommez les choses par ce à quoi elles sont destinées et non par ce qu'elles sont.
  3. Rappelez-vous toujours que le code est lu plus qu'il n'est écrit.

Ainsi, la signature de méthode optimale, à mon avis, serait:

Range Pad(Range toPad)

Raccourcir le nom de la méthode va de soi.

Le nom du paramètre toPad indique immédiatement au lecteur que ce paramètre va probablement être modifié sur place en étant complété, puis renvoyé. En revanche, aucune hypothèse ne peut être faite sur une variable nommée range.

De plus, dans le corps réel de la méthode, toute autre variable Range introduite serait (devrait) être nommée par son intention, donc vous pourriez avoir padded et unpadded. .. toPad est conforme à ces conventions de dénomination, mais range ne fait que coller et ne gèle pas.

9
Ian Kemp

Pour nommer les éléments de code (types, variables, fonctions, quoi que ce soit), la question clé à vous poser est

Si je fais une faute de frappe, le compilateur la trouvera-t-il pour moi?

Le pire type de bogue basé sur une faute de frappe est celui où le code se compile et s'exécute, mais donne un comportement différent de ce que vous attendez, pour des raisons subtiles. Et comme c'est dû à une faute de frappe, il est généralement très difficile de voir quand vous inspectez le code. Si une faute de frappe arrête la compilation du code, le compilateur signalera la ligne à l'origine du problème et vous pourrez facilement la trouver et la corriger.

Pour votre situation où le type et la variable ne diffèrent qu'en capitalisation, ce sera toujours le cas. (Ou presque toujours - avec suffisamment d'efforts, je suis sûr que vous pourriez le faire fonctionner, mais vous devriez vraiment essayer.) Je pense donc que vous êtes bien là.

Si vous deviez vous inquiéter, il y aurait deux variables, méthodes, fonctions ou propriétés dans la portée actuelle appelées range et Range. Dans ce cas, le compilateur le laissera probablement passer et vous obtiendrez un comportement inattendu au moment de l'exécution. Notez que ce sont deux des types de ces types d'élément de code, pas seulement "deux variables" ou "deux fonctions" - tous ces éléments peuvent être implicitement transtypés les uns aux autres, avec le carnage résultant lors de son exécution. Vous pourriez recevoir des avertissements, mais vous ne pouvez rien garantir de plus que cela. Vous avez des problèmes similaires si vous aviez déclaré deux types appelés range et Range.

Notez également que la même chose s'applique au style notation hongroise , où les noms sont préfixés par un ou plusieurs caractères pour en dire plus sur ce que c'est. Si vous avez une variable appelée Range et un pointeur vers elle appelée PRange, il est facile de manquer accidentellement le P, par exemple. C # devrait attraper cela, mais C et C++ ne vous donneront qu'un avertissement au maximum. Ou plus inquiétant, supposons que vous ayez une version double appelée DRange et que vous sous-échantillonniez celle-ci en une version flottante appelée FRange. Utilisez le float one par accident (ce qui est facile car les touches sont adjacentes sur un clavier) et votre code fonctionnera , mais il tombera de façon étrange et imprévisible lorsque le processus est à court de résolution et de sous-flux.

Nous ne sommes plus à l'époque où nous avions des limites de nommage de 8 caractères, ou 16 caractères, ou quelque limite arbitraire que ce soit. J'ai parfois entendu des novices se plaindre de noms de variables plus longs, ce qui rend le codage plus long. Mais ce ne sont que les novices qui s'en plaignent. Les codeurs sérieux savent que ce qui prend vraiment du temps est de trouver des bugs obscurs - et un mauvais choix de nom est un moyen classique de vous laisser tomber dans ce trou particulier.

3
Graham

Je voudrais ajouter une anecdote, tandis que Range range ceci est syntaxiquement légal, cela pourrait rendre les choses plus difficiles à déboguer ou à refactoriser. Vous recherchez cette variable nommée "plage" dans un fichier avec beaucoup de variables de type Plage? Vous pouvez finir par faire plus de travail plus tard à la suite de ce choix de nom.

Cependant, cela dépend largement du contexte. S'il s'agit d'un fichier de 30 lignes, mes déclarations n'entrent pas vraiment en jeu.

1
Jacob M.

Je pense que vous pouvez utiliser Range range nowdays pour une raison: la coloration syntaxique. Les IDE modernes mettent généralement en évidence les noms de type et les noms de paramètre dans différentes couleurs. De plus, un type et une variable ont une "distance logique" considérable à ne pas confondre facilement.

Si ce n'était pas le cas, j'envisagerais un nom différent ou j'essaierais d'activer un plugin/extension capable de mettre en évidence cette syntaxe.

1
akaltar

Lorsqu'une fonction est générique, il va de soi que les paramètres seront génériques et devraient donc avoir des noms génériques.

Pas ce que vous dites, mais j'ai vu des fonctions qui exécutent une fonction générique qui ont des noms de paramètres qui sont trompeusement spécifiques. Comme

public String removeNonDigits(String phoneNumber)

Le nom de la fonction semble très générique, comme ceci pourrait être appliqué à de nombreuses chaînes dans de nombreuses situations. Mais le nom du paramètre est étrangement spécifique, ce qui me fait me demander si le nom de la fonction est trompeur, ou ... quoi?

Alors bien sûr, au lieu de dire Range range, vous pourriez dire Range rangeToPad. Mais quelles informations cela ajoute-t-il? Bien sûr, c'est la plage à garnir. Que serait-ce d'autre?

L'ajout d'un préfixe arbitraire, "mon" ou "m_" ou autre, ne transmet aucune information supplémentaire au lecteur. Quand j'ai utilisé des langues où le compilateur ne permet pas qu'un nom de variable soit le même qu'un nom de type - avec ou sans respect de la casse - j'ai parfois mis un préfixe ou un suffixe, juste pour le faire compiler . Mais c'est juste pour satisfaire le compilateur. On pourrait soutenir que même si le compilateur peut distinguer, cela facilite la distinction pour un lecteur humain. Mais wow, en Java j'ai écrit des déclarations comme "Customer customer = new Customer ();" un milliard de fois et je n'ai jamais trouvé cela déroutant. (Je l'ai toujours trouvé un peu redondant) et j'aime plutôt cela dans VB vous pouvez simplement dire "dim client comme nouveau client" et vous n'avez pas à donner le nom de la classe deux fois.)

Là où je m'oppose fortement aux noms génériques, c'est quand il y a deux ou plusieurs instances du même type dans la même fonction. PARTICULIÈREMENT les paramètres. Comme:

public Range pad(Range range1, Range range2)

Quelle est la différence entre range1 et range2? Comment suis-je censé savoir? Si c'est quelque chose où ils sont vraiment deux valeurs génériques et interchangeables, d'accord, comme

public boolean overlap(Range range1, Range range2)

Je m'attendrais à ce que cela renvoie true si les plages se chevauchent et false dans le cas contraire, elles sont donc génériques et interchangeables.

Mais s'ils sont différents, donnez-moi un indice sur la façon dont ils sont différents! Je travaillais récemment sur un programme qui avait une classe "Place" pour contenir des données sur les lieux géographiques, et avec des variables de ce type nommées "p", "place", "place2", "myPlace", etc. Wow, ceux les noms m'aident vraiment à déterminer lequel est lequel.

0
Jay