Convention de dénomination - trait de soulignement dans les variables C ++ et C #

146

Il est courant de voir un _varnom de variable dans un champ de classe. Que signifie le trait de soulignement? Existe-t-il une référence pour toutes ces conventions de dénomination spéciales?

Stan
la source
17
Certaines directives de codage d'entreprise malavisées suggèrent d'ajouter des verrues aux variables membres pour les distinguer des variables locales, par conviction que les classes et les fonctions vont inévitablement devenir tellement gonflées que vous ne pouvez pas garder une trace de ce qui se passe sans de vagues indices comme celui-ci. Les personnes qui suggèrent de telles conventions sont trop souvent celles dont le code en a le plus besoin.
Mike Seymour
26
@Mike - Votre déclaration générale n'est tout simplement pas vraie. J'ai trouvé que l'utilisation de cette convention rend beaucoup plus facile l'analyse rapide des méthodes et une bonne compréhension de la classe.
ChaosPandion
12
@ChaosPandion: alors ne le lisez pas comme une déclaration générale. «Certains» ne veut pas dire «tout», et «trop souvent» ne veut pas dire «toujours», et peut-être que vous faites exception à mon expérience.
Mike Seymour
17
En C ++, évitez les traits de soulignement en tête . Dans de nombreux contextes (c'est-à-dire à portée globale, lorsqu'une lettre majuscule suit, etc.), ils sont réservés à l'implémentation, et vous risquez en fait d'avoir des macros les piétiner. Donc, si vous les voulez, faites-leur des traits de soulignement à la fin .
sbi

Réponses:

120

Le trait de soulignement est simplement une convention; rien de plus. En tant que tel, son utilisation est toujours quelque peu différente pour chaque personne. Voici comment je les comprends pour les deux langues en question:

En C ++, un trait de soulignement indique généralement une variable de membre privé.

En C #, je le vois généralement utilisé uniquement lors de la définition de la variable de membre privé sous-jacente pour une propriété publique. Les autres variables de membre privé n'auraient pas de trait de soulignement. Cependant, cet usage a largement disparu avec l'avènement des propriétés automatiques.

Avant:

private string _name;
public string Name
{
    get { return this._name; }
    set { this._name = value; }
}

Après:

public string Name { get; set; }
jdmichal
la source
11
Sauf pour les équipes qui souhaitent que leurs propriétés soient immuables.
ChaosPandion
11
Les identificateurs commençant par des traits de soulignement sont réservés au compilateur. L'utilisation de traits de soulignement de préfixe peut entrer en conflit avec les symboles du compilateur.
Thomas Matthews
12
@Thomas Matthews - pas en C #.
EMP le
11
@ChaosPandion Je suppose que ce que vous entendez par «immuable» est en fait «en lecture seule», auquel cas on peut utiliser public string Name { get; private set; }. Certes, ce n'est pas parfaitement immuable, mais c'est là.
jdmichal
7
@Thomas Dans un contexte de classe, identifiants commençant par des traits de soulignement suivis d'une majuscule a réservée en C ++. _varn'est pas réservé.
Tyler McHenry
84

Il est recommandé de NE PAS utiliser UNDERSCORES avant tout nom de variable ou nom de paramètre en C ++

Les noms commençant par un trait de soulignement ou un double trait de soulignement sont RÉSERVÉS aux implémenteurs C ++. Les noms avec un trait de soulignement sont réservés au fonctionnement de la bibliothèque.

Si vous avez une lecture de la norme de codage C ++, vous verrez que dans la toute première page, il est dit:

"Ne pas trop légiférer sur la dénomination, mais utilisez une convention de dénomination cohérente: il n'y a que deux choses à faire: a) ne jamais utiliser de" noms sournois ", ceux qui commencent par un trait de soulignement ou qui contiennent un double trait de soulignement;" (p2, normes de codage C ++, Herb Sutter et Andrei Alexandrescu)

Plus précisément, le projet de travail de l' ISO énonce les règles actuelles:

De plus, certains identificateurs sont réservés à l'usage des implémentations C ++ et ne doivent pas être utilisés autrement; aucun diagnostic n'est requis. (a) Chaque identifiant contenant un double trait de soulignement __ ou commençant par un trait de soulignement suivi d'une lettre majuscule est réservé à l'implémentation pour toute utilisation. (b) Chaque identificateur qui commence par un trait de soulignement est réservé à l'implémentation pour être utilisé comme nom dans l'espace de noms global.

Il est recommandé d'éviter de commencer un symbole par un trait de soulignement au cas où vous vous retrouveriez accidentellement dans l'une des limitations ci-dessus.

Vous pouvez voir par vous-même pourquoi une telle utilisation de traits de soulignement peut être désastreuse lors du développement d'un logiciel:

Essayez de compiler un simple programme helloWorld.cpp comme ceci:

g++ -E helloWorld.cpp

Vous verrez tout ce qui se passe en arrière-plan. Voici un extrait:

   ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
   try
     {
       __streambuf_type* __sb = this->rdbuf();
       if (__sb)
  {
    if (__sb->pubsync() == -1)
      __err |= ios_base::badbit;
    else
      __ret = 0;
  }

Vous pouvez voir combien de noms commencent par un double tiret bas!

De plus, si vous regardez les fonctions membres virtuelles, vous verrez que * _vptr est le pointeur généré pour la table virtuelle qui est automatiquement créée lorsque vous utilisez une ou plusieurs fonctions membres virtuelles dans votre classe! Mais c'est une autre histoire ...

Si vous utilisez des traits de soulignement, vous pourriez avoir des problèmes de conflit et vous n'aurez AUCUNE IDÉE de la cause, jusqu'à ce qu'il soit trop tard.

Constantinos Glynos
la source
4
Les noms qui ne sont pas globaux ou de portée de fichier et qui commencent par un trait de soulignement et une lettre minuscule ne conviennent-ils pas parfaitement? Je fais cela tout le temps parce que c'est très propre pour des cas spécifiques, par exemple: void A :: set_size (int _size) {size = _size; }. Que faites-vous pour des utilisations triviales comme celle-ci?
tukra
3
Le soulignement suivi d'une lettre minuscule est autorisé dans la portée non globale / fichier, je crois. Pouvez-vous me montrer où dans la norme il est dit que ce n'est pas le cas? Le problème avec le trait de soulignement de fin est que je l'utilise déjà parfois pour les variables membres. Donc je pourrais avoir la fonction 'int size ();' membre var 'int size_;' et l'argument 'int _size'. Cela a tendance à bien couvrir les choses et je n'ai pas vu de meilleures alternatives. Les fonctions majuscules ne sont pas possibles pour les génériques qui fonctionnent avec STL. Le style 'this.size' que les gens aiment en C # me semble sujet aux erreurs à moins que vous ne l'utilisiez toujours pour l'accès aux membres, ce qui est moche.
tukra
7
Je comprends que certaines personnes ne souhaitent pas utiliser de soulignement et une lettre minuscule parce qu'elles peuvent avoir du mal à comprendre ce qui est légal. Le standard C ++ le permet même si certains auteurs recommandent de ne pas l'utiliser. Pour moi, puisque c'est totalement légal et non réservé, je ne vois aucune raison de le considérer comme risqué. Merci pour vos commentaires.
tukra
3
@tukra: Ce n'est pas entièrement légal. La norme C ++ vous permet uniquement d'utiliser un seul trait de soulignement suivi d'une lettre minuscule dans la portée locale. Bonne chance! :-)
Constantinos Glynos
4
Désolé. Je pensais que nous n'avions plus besoin de répéter les qualifications. Un identificateur C ++ commençant par un trait de soulignement suivi d'une lettre minuscule est autorisé dans toutes les étendues autres que l'étendue de fichier. Il est sûr et légal dans les fonctions, les prototypes de fonctions, les classes, les structures, les unions, les énumérations et tout ce que vous mettez dans un espace de noms. Si vous suivez la pratique courante consistant à placer tout votre code dans des espaces de noms, vous êtes complètement en sécurité.
tukra
45

En fait, la _varconvention vient de VB et non de C # ou C ++ (m _, ... est autre chose).

Cela a permis de surmonter l'insensibilité à la casse de VB lors de la déclaration de propriétés.

Par exemple, un tel code n'est pas possible dans VB car il considère useret Usercomme le même identifiant

Private user As String

Public Property User As String
  Get
    Return user
  End Get
  Set(ByVal Value As String)
    user = value
  End Set
End Property

Donc pour surmonter cela, certains ont utilisé une convention pour ajouter '_' au champ privé pour venir comme ça

Private _user As String

Public Property User As String
  Get
    Return _user
  End Get
  Set(ByVal Value As String)
    _user = value
  End Set
End Property

Étant donné que de nombreuses conventions sont pour .Net et pour conserver une certaine uniformité entre les conventions C # et VB.NET, elles utilisent la même.

J'ai trouvé la référence de ce que je disais: http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices

Étui de chameau avec soulignement principal. Dans VB.NET, indiquez toujours «Protected» ou «Private», n'utilisez pas «Dim». L'utilisation de "m_" est déconseillée, tout comme l'utilisation d'un nom de variable qui diffère de la propriété uniquement par casse, en particulier avec des variables protégées car cela enfreint la conformité, et vous rendra la vie difficile si vous programmez dans VB.NET, comme vous devrait nommer vos membres différemment des propriétés de l'accesseur / mutateur. De tous les éléments ici, le trait de soulignement principal est vraiment le seul controversé. Personnellement, je préfère cela au cas de chameau sans trait de soulignement pour mes variables privées afin que je n'ai pas à qualifier les noms de variables avec «ceci». pour distinguer des paramètres dans les constructeurs ou ailleurs où j'aurai probablement une collision de noms. Avec l'insensibilité à la casse de VB.NET, cela est d'autant plus important que vos propriétés d'accesseur auront généralement le même nom que vos variables de membre privé à l'exception du trait de soulignement. Pour ce qui est de m_, il ne s'agit en réalité que d'esthétique. Moi (et beaucoup d'autres) trouve m_ laid, car il semble qu'il y ait un trou dans le nom de la variable. C'est presque offensant. J'avais l'habitude de l'utiliser tout le temps dans VB6, mais c'était uniquement parce que les variables ne pouvaient pas avoir de trait de soulignement principal. Je ne pourrais pas être plus heureux de le voir disparaître. Microsoft déconseille le m_ (et le simple _) même s'ils ont fait les deux dans leur code. En outre, le préfixe avec un "m" droit est tout à fait correct. Bien sûr, comme ils codent principalement en C #, ils peuvent avoir des membres privés qui ne diffèrent que par le cas des propriétés. Les gens de VB doivent faire autre chose. Plutôt que d'essayer de proposer des cas spéciaux langue par langue, je recommande le trait de soulignement principal pour toutes les langues qui le prendront en charge. Si je veux que ma classe soit entièrement compatible CLS, je peux laisser le préfixe sur toutes les variables membres protégées C #. Dans la pratique, cependant, je ne m'inquiète jamais à ce sujet car je garde toutes les variables membres potentiellement protégées privées et fournit à la place des accesseurs et des mutateurs protégés. Pourquoi: En un mot, cette convention est simple (un caractère), facile à lire (votre œil n'est pas distrait par les autres caractères principaux) et évite avec succès les collisions de noms avec les variables au niveau de la procédure et les propriétés au niveau de la classe. . Je recommande le trait de soulignement principal pour toutes les langues qui le prendront en charge. Si je veux que ma classe soit entièrement compatible CLS, je peux laisser le préfixe sur toutes les variables membres protégées C #. Dans la pratique, cependant, je ne m'inquiète jamais à ce sujet car je garde toutes les variables membres potentiellement protégées privées et fournit à la place des accesseurs et des mutateurs protégés. Pourquoi: En un mot, cette convention est simple (un caractère), facile à lire (votre œil n'est pas distrait par les autres caractères principaux) et évite avec succès les collisions de noms avec les variables au niveau de la procédure et les propriétés au niveau de la classe. . Je recommande le trait de soulignement principal pour toutes les langues qui le prendront en charge. Si je veux que ma classe soit entièrement compatible CLS, je peux laisser le préfixe sur toutes les variables membres protégées C #. Dans la pratique, cependant, je ne m'inquiète jamais à ce sujet car je garde toutes les variables membres potentiellement protégées privées et fournit à la place des accesseurs et des mutateurs protégés. Pourquoi: En un mot, cette convention est simple (un caractère), facile à lire (votre œil n'est pas distrait par les autres caractères principaux) et évite avec succès les collisions de noms avec les variables au niveau de la procédure et les propriétés au niveau de la classe. . Je ne m'inquiète jamais à ce sujet car je garde toutes les variables de membre potentiellement protégées privées et fournit à la place des accesseurs et des mutateurs protégés. Pourquoi: En un mot, cette convention est simple (un caractère), facile à lire (votre œil n'est pas distrait par les autres caractères principaux) et évite avec succès les collisions de noms avec les variables au niveau de la procédure et les propriétés au niveau de la classe. . Je ne m'inquiète jamais à ce sujet car je garde toutes les variables de membre potentiellement protégées privées et fournit à la place des accesseurs et des mutateurs protégés. Pourquoi: En un mot, cette convention est simple (un caractère), facile à lire (votre œil n'est pas distrait par les autres caractères de tête) et évite avec succès les collisions de noms avec les variables de niveau procédure et les propriétés de niveau classe. .

Zied
la source
6

Le premier commentateur (R Samuel Klatchko) a référencé: Quelles sont les règles d'utilisation d'un trait de soulignement dans un identifiant C ++? qui répond à la question sur le trait de soulignement en C ++. En général, vous n'êtes pas censé utiliser un trait de soulignement au début, car il est réservé à l'implémenteur de votre compilateur. Le code que vous voyez _varest probablement soit du code hérité, soit du code écrit par quelqu'un qui a grandi en utilisant l'ancien système de dénomination qui n'a pas froncé les sourcils sur les principaux traits de soulignement.

Comme d'autres réponses l'indiquent, il était utilisé en C ++ pour identifier les variables de membre de classe. Cependant, cela n'a pas de signification particulière en ce qui concerne les décorateurs ou la syntaxe. Donc, si vous voulez l'utiliser, il se compilera.

Je vais laisser la discussion C # aux autres.

bsruth
la source
5

_var n'a aucune signification et sert uniquement à faciliter la distinction entre le fait que la variable est une variable de membre privé.

En C ++, utiliser la convention _var est une mauvaise forme, car il existe des règles régissant l'utilisation du trait de soulignement devant un identificateur. _var est réservé comme identifiant global, tandis que _Var (trait de soulignement + majuscule) est réservé à tout moment. C'est pourquoi en C ++, vous verrez des gens utiliser la convention var_ à la place.

5ound
la source
4

Vous pouvez créer vos propres directives de codage. Rédigez simplement une documentation claire pour le reste de l'équipe.

L'utilisation de _field aide Intelilsense à filtrer toutes les variables de classe en tapant simplement _.

Je suis généralement les directives de Brad Adams , mais il recommande de ne pas utiliser de soulignement.

Tony Alexander Hild
la source
2

La norme nommant Microsoft C # indique les variables et les paramètres doivent utiliser la forme inférieure de cas de chameau IE: paramName . La norme exige également des champs à suivre la même forme , mais cela peut conduire à un code peu clair tant d'équipes appellent à un préfixe de soulignement pour améliorer la clarté IE: _fieldName .

ChaosPandion
la source
2

Avec C #, les directives de conception de Microsoft Framework suggèrent de ne pas utiliser le caractère de soulignement pour les membres publics . Pour les membres privés , les traits de soulignement peuvent être utilisés. En fait, Jeffrey Richter (souvent cité dans les directives) utilise un m_ par exemple et un «s_» pour les membres statiques privés.

Personnellement, j'utilise juste _ pour marquer mes membres privés. "m_" et "s_" frôlent la notation hongroise qui n'est pas seulement désapprouvée dans .NET, mais peut être assez verbeuse et je trouve que les classes avec de nombreux membres ont du mal à faire un scan rapide des yeux par ordre alphabétique (imaginez 10 variables commençant toutes par m_) .

P.Brian.Mackey
la source
Puisque la notation hongroise indique le type, je ne pense pas que vous puissiez vraiment dire que m / s est à la limite.
Jerry Nixon
@ JerryNixon-MSFT Identifions-nous le type de données variable et le type de visibilité variable comme la même chose en ce qui concerne la notion hongroise?
Necro
1

J'utilise la dénomination _var pour les variables membres de mes classes. Il y a 2 raisons principales pour lesquelles je fais:

1) Cela m'aide à garder une trace des variables de classe et des variables de fonction locales lorsque je lis mon code plus tard.

2) Cela aide Intellisense (ou tout autre système de complétion de code) lorsque je recherche une variable de classe. Le simple fait de connaître le premier caractère est utile pour filtrer la liste des variables et méthodes disponibles.

UN J
la source
1
Il est difficile dans une méthode plus large de s'appuyer sur l'intellisense de survol ou sur l'analyse pour voir si une variable est définie localement ou non. Préférez également "__" pour la statique pour les mêmes raisons que vous mentionnez mais il est actuellement en disgrâce.
crokusek
1

En ce qui concerne les langages C et C ++, il n'y a pas de signification particulière à un trait de soulignement dans le nom (début, milieu ou fin). C'est juste un caractère de nom de variable valide. Les «conventions» proviennent de pratiques de codage au sein d'une communauté de codage.

Comme déjà indiqué par divers exemples ci-dessus, _ au début peut signifier des membres privés ou protégés d'une classe en C ++.

Permettez-moi de vous donner une histoire qui pourrait être des anecdotes amusantes. Sous UNIX, si vous avez une fonction de bibliothèque de base C et un back-end du noyau où vous voulez également exposer la fonction du noyau à l'espace utilisateur, le _ est bloqué devant le stub de fonction qui appelle directement la fonction du noyau sans rien faire d'autre. L'exemple le plus célèbre et le plus familier de ceci est exit () vs _exit () sous les noyaux de type BSD et SysV: là, exit () fait des choses sur l'espace utilisateur avant d'appeler le service de sortie du noyau, alors que _exit correspond simplement au service de sortie du noyau.

Donc _ a été utilisé pour les trucs "locaux" dans ce cas, local étant localement à la machine. En général, les fonctions _functions () n'étaient pas portables. En cela, vous ne devriez pas vous attendre au même comportement sur différentes plates-formes.

Maintenant, comme pour _ dans les noms de variables, tels que

int _foo;

Eh bien psychologiquement, un _ est une chose étrange à taper au début. Donc, si vous voulez créer un nom de variable qui aurait moins de chance de heurter quelque chose d'autre, PARTICULIÈREMENT lorsque vous traitez avec des substitutions pré-processeurs, vous voulez considérer les utilisations de _.

Mon conseil de base serait de toujours suivre la convention de votre communauté de codage, afin que vous puissiez collaborer plus efficacement.

Roi elfe
la source
0

Cela signifie simplement que c'est un champ membre de la classe.

hkon
la source
0

Il n'y a pas de convention de dénomination particulière, mais je l'ai vu pour les membres privés.

Cade Roux
la source
0

Beaucoup de gens aiment que les champs privés soient précédés d'un trait de soulignement. C'est juste une convention de dénomination.

Les conventions de dénomination «officielles» de C # prescrivent des noms simples en minuscules (sans trait de soulignement) pour les champs privés.

Je ne connais pas les conventions standard pour C ++, bien que les traits de soulignement soient très largement utilisés.

Mau
la source
0

C'est juste une convention que certains programmeurs utilisent pour préciser lorsque vous manipulez un membre de la classe ou un autre type de variable (paramètres, local de la fonction, etc.). Une autre convention qui est également largement utilisée pour les variables membres est le préfixe du nom avec «m_».

Quoi qu'il en soit, ce ne sont que des conventions et vous ne trouverez pas une seule source pour toutes. C'est une question de style et chaque équipe de programmation, projet ou entreprise a le sien (ou même n'en a pas).

Goedson
la source
0

Il y a une raison tout à fait légitime de l'utiliser en C #: si le code doit également être extensible à partir de VB.NET. (Sinon, je ne le ferais pas.)

Puisque VB.NET est insensible à la casse, il n'y a pas de moyen simple d'accéder au fieldmembre protégé dans ce code:

public class CSharpClass
{
    protected int field;
    public int Field { get { return field; } }
}

Par exemple, cela accédera au getter de propriété, pas au champ:

Public Class VBClass
    Inherits CSharpClass

    Function Test() As Integer
        Return Field
    End Function

End Class

Heck, je ne peux même pas écrire fielden minuscules - VS 2010 ne cesse de le corriger.

Afin de le rendre facilement accessible aux classes dérivées dans VB.NET, il faut trouver une autre convention de dénomination. Le préfixe d'un trait de soulignement est probablement le moins intrusif et le plus "historiquement accepté" d'entre eux.

Andras Vass
la source
0

Maintenant, la notation utilisant "this" comme dans this.foobarbaz est acceptable pour les variables membres de la classe C #. Il remplace l'ancienne notation «m_» ou simplement «__». Cela rend le code plus lisible car il n'y a aucun doute sur la référence.

ddm
la source
0

D'après mon expérience (certainement limitée), un trait de soulignement indiquera qu'il s'agit d'une variable de membre privé. Comme l'a dit Gollum, cela dépendra de l'équipe, cependant.

Smashery
la source
0

Ancienne question, nouvelle réponse (C #).

Une autre utilisation des traits de soulignement pour C # est avec la DI d'ASP NET Core (injection de dépendances). Les readonlyvariables privées d'une classe qui ont été affectées à l'interface injectée pendant la construction doivent commencer par un trait de soulignement. Je suppose que c'est un débat pour savoir s'il faut utiliser le trait de soulignement pour chaque membre privé d'une classe (bien que Microsoft lui-même le suive), mais celui-ci est certain.

private readonly ILogger<MyDependency> _logger;

public MyDependency(ILogger<MyDependency> logger)
{
    _logger = logger;
}
Barry Guvenkaya
la source
-2

Une convention de dénomination comme celle-ci est utile lorsque vous lisez du code, en particulier du code qui ne vous appartient pas. Une convention de dénomination forte permet d'indiquer où un membre particulier est défini, de quel type de membre il s'agit, etc. La plupart des équipes de développement adoptent une convention de dénomination simple et préfixent simplement les champs de membre avec un trait de soulignement ( _fieldName). Dans le passé, j'ai utilisé la convention de dénomination suivante pour C # (qui est basée sur les conventions Microsofts pour le code du framework .NET, qui peut être vue avec Reflector):

Champ d'instance: m_fieldName
Champ statique: s_fieldName Membre
public / protégé / interne: PascalCasedName ()
Membre privé: camelCasedName ()

Cela aide les gens à comprendre la structure, l'utilisation, l'accessibilité et l'emplacement des membres lorsqu'ils lisent très rapidement du code inconnu.

jrista
la source
3
En fait, Microsoft ne recommande pas d'utiliser les préfixes m_, s_. N'utilisez pas de préfixe pour les noms de champ. Par exemple, n'utilisez pas g_ ou s_ pour distinguer les champs statiques des champs non statiques. msdn.microsoft.com/en-us/library/ms229012.aspx
Zied le
1
Comme je l'ai dit, jetez un œil à leur code source avec Reflector. Vous serez surpris de voir à quel point ils se soustraient à leurs propres recommandations. ;) Comme mon article l'a mentionné, cela aide à améliorer la lisibilité de votre code, et ma dernière équipe a vraiment aimé la convention de dénomination ci-dessus.
jrista