Convenção de nomenclatura - sublinhado nas variáveis ​​C ++ e C #


146

É comum ver um _varnome de variável em um campo de classe. O que significa o sublinhado? Existe uma referência para todas essas convenções de nomenclatura especiais?



17
Algumas diretrizes de codificação corporativa equivocadas sugerem a adição de verrugas às variáveis-membro para distingui-las das variáveis ​​locais, com a crença de que classes e funções inevitavelmente crescerão tão inchadas que você não pode acompanhar o que há sem pistas vagas como essa. As pessoas que sugerem tais convenções geralmente são aquelas cujo código mais precisa delas.
Mike Seymour

26
@ Mike - Sua declaração geral não é verdadeira. Descobri que o uso dessa convenção facilita muito a verificação rápida dos métodos e o entendimento da classe.
ChaosPandion

12
@ ChaosPandion: então não o leia como uma declaração geral. "Alguns" não significa "todos" e "com muita frequência" não significa "sempre", e talvez você seja uma exceção à minha experiência.
Mike Seymour

17
No C ++, evite sublinhados à esquerda . Em muitos contextos (isto é, no escopo global, quando uma letra maiúscula segue etc.), eles são reservados para a implementação, e você corre o risco de ter alguma macro pisoteada sobre eles. Portanto, se você os quiser, faça com que sejam sublinhados à direita .
SBI

Respostas:


120

O sublinhado é simplesmente uma convenção; nada mais. Como tal, seu uso é sempre um pouco diferente para cada pessoa. Veja como eu os entendo para os dois idiomas em questão:

No C ++, um sublinhado geralmente indica uma variável de membro particular.

Em C #, normalmente vejo isso usado apenas ao definir a variável de membro privado subjacente para uma propriedade pública. Outras variáveis ​​de membro privado não teriam um sublinhado. Esse uso foi largamente esquecido com o advento das propriedades automáticas.

Antes:

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

Depois de:

public string Name { get; set; }

11
Exceto para equipes que desejam que suas propriedades sejam imutáveis.
ChaosPandion

11
Identificadores iniciando com sublinhados são reservados para o compilador. O uso de sublinhados de prefixo pode entrar em conflito com os símbolos do compilador.
Thomas Matthews

12
@ Thomas Matthews - não em C #.
EMP

11
@ChaosPandion Estou assumindo que o que você quer dizer com "imutável" é na verdade "somente leitura"; nesse caso, pode-se usar public string Name { get; private set; }. É verdade que não é perfeitamente imutável, mas está lá.
Jdmichal

7
@ Thomas Em um contexto de classe, identificadores começando com sublinhados seguidos por uma letra maiúscula a reservada em C ++. _varnão está reservado.
Tyler McHenry

84

É uma prática recomendada NÃO usar UNDERSCORES antes de qualquer nome de variável ou parâmetro em C ++

Nomes começando com um sublinhado ou um sublinhado duplo são RESERVADOS para os implementadores de C ++. Os nomes com sublinhado são reservados para a biblioteca funcionar.

Se você tiver uma leitura no C ++ Coding Standard, verá que na primeira página diz:

"Não exagere na nomeação em excesso, mas use uma convenção de nomenclatura consistente: existem apenas dois itens obrigatórios: a) nunca use" nomes ocultos ", aqueles que começam com um sublinhado ou que contêm um sublinhado duplo;" (p2, padrões de codificação C ++, Herb Sutter e Andrei Alexandrescu)

Mais especificamente, o rascunho de trabalho da ISO indica as regras reais:

Além disso, alguns identificadores são reservados para uso em implementações de C ++ e não devem ser usados ​​de outra forma; nenhum diagnóstico é necessário. (a) Cada identificador que contém um sublinhado duplo __ ou começa com um sublinhado seguido por uma letra maiúscula é reservado à implementação para qualquer uso. (b) Cada identificador que começa com um sublinhado é reservado à implementação para uso como um nome no espaço para nome global.

É uma prática recomendada evitar o início de um símbolo com um sublinhado, caso você acidentalmente vagueie por uma das limitações acima.

Você pode ver por si mesmo por que esse uso de sublinhados pode ser desastroso ao desenvolver um software:

Tente compilar um programa helloWorld.cpp simples como este:

g++ -E helloWorld.cpp

Você verá tudo o que acontece em segundo plano. Aqui está um trecho:

   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;
  }

Você pode ver quantos nomes começam com um sublinhado duplo!

Além disso, se você observar as funções membro virtuais, verá que * _vptr é o ponteiro gerado para a tabela virtual que é criada automaticamente quando você usa uma ou mais funções membro virtuais em sua classe! Mas isso é outra história ...

Se você usar sublinhados, poderá entrar em problemas de conflito e não terá idéia do que está causando isso, até que seja tarde demais.


4
Os nomes que não são globais ou com escopo de arquivo e começam com sublinhado e uma letra minúscula são perfeitamente adequados? Eu faço isso o tempo todo porque é muito limpo para casos específicos, por exemplo: void A :: set_size (tamanho_ int_tamanho) {size = _size; } O que você faz para usos triviais como este?
Tukra

3
Sublinhado seguido por uma letra minúscula é permitido no escopo não global / de arquivo, acredito. Você pode me mostrar onde no padrão ele diz que não é? O problema com o sublinhado à direita é que eu já uso isso para vários membros, às vezes. Então eu posso ter a função 'int size ();' membro var 'int size_;' e argumento 'int _size'. Isso tende a cobrir bem as coisas e eu não vi alternativas melhores. Funções maiúsculas não são possíveis para genéricos que funcionam com STL. O estilo 'this.size' que as pessoas do C # gostam parece propenso a erros, a menos que você sempre o use para acesso de membros que é feio.
Tukra

7
Entendo que algumas pessoas não desejam usar sublinhado e uma letra minúscula porque podem ter problemas para manter claro o que é legal. O padrão C ++ permite isso mesmo que alguns autores recomendem não usá-lo. Para mim, como é totalmente legal e não reservado, não vejo motivo para considerá-lo arriscado. Obrigado pelo seu feedback!
Tukra

3
@ tukra: Não é totalmente legal. O padrão C ++ permite apenas que você use um único sublinhado seguido por uma letra minúscula no escopo local. Boa sorte! :-)
Constantinos Glynos 23/11

4
Desculpe. Pensei que estávamos precisando repetir as qualificações. Um identificador C ++ começando com um sublinhado seguido por uma letra minúscula é permitido em todos os escopos, exceto no escopo do arquivo. É seguro e legal em funções, protótipos de funções, classes, estruturas, uniões, enumerações e tudo o que você coloca em um espaço para nome. Se você seguir a prática comum de colocar todo o seu código nos espaços para nome, estará totalmente seguro.
Tukra

45

Na verdade, a _varconvenção vem do VB e não do C # ou C ++ (m _, ... é outra coisa).

Isso veio para superar a insensibilidade do VB ao declarar Propriedades.

Por exemplo, esse código não é possível no VB porque considera usere Usercomo o mesmo identificador

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

Então, para superar isso, alguns usaram uma convenção para adicionar '_' ao campo privado e assim

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

Como muitas convenções são para .Net e para manter alguma uniformidade entre as convenções C # e VB.NET, elas estão usando a mesma.

Encontrei a referência para o que estava dizendo: http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices

Camel Case com sublinhado principal. No VB.NET, sempre indique "Protegido" ou "Privado", não use "Dim". O uso de "m_" é desencorajado, assim como o uso de um nome de variável que difere da propriedade apenas por caso, especialmente com variáveis ​​protegidas, pois isso viola a conformidade e tornará sua vida uma dor se você programar no VB.NET, como você teria que nomear seus membros como algo diferente das propriedades de acessador / mutador. De todos os itens aqui, o principal sublinhado é realmente o único controverso. Pessoalmente, prefiro isso ao invés de um caso de camelo sem sublinhado direto para minhas variáveis ​​privadas, para que eu não precise qualificar nomes de variáveis ​​com "isto". para distinguir dos parâmetros em construtores ou em outros lugares onde provavelmente terei uma colisão de nomes. Com a distinção entre maiúsculas e minúsculas do VB.NET, isso é ainda mais importante, pois suas propriedades de acessador geralmente terão o mesmo nome que suas variáveis ​​de membro privadas, exceto o sublinhado. No que diz respeito a m_, é realmente apenas estética. Eu (e muitos outros) acho feio, pois parece que há um buraco no nome da variável. É quase ofensivo. Eu costumava usá-lo no VB6 o tempo todo, mas isso era apenas porque as variáveis ​​não podiam ter um sublinhado à esquerda. Eu não poderia estar mais feliz em vê-lo desaparecer. A Microsoft recomenda contra o m_ (e o _ direto), embora eles tenham feito os dois no código. Além disso, o prefixo com um "m" reto está correto. Obviamente, como codificam principalmente em C #, eles podem ter membros particulares que diferem apenas no caso das propriedades. O pessoal da VB precisa fazer outra coisa. Em vez de tentar criar casos especiais de idioma por idioma, recomendo o sublinhado principal para todos os idiomas que o suportam. Se eu quiser que minha classe seja totalmente compatível com CLS, poderia deixar de fora o prefixo em qualquer variável de membro protegida por C #. Na prática, no entanto, nunca me preocupo com isso, pois mantenho todas as variáveis ​​de membro potencialmente protegidas privadas e forneço acessores e mutadores protegidos. Por que: Em poucas palavras, esta convenção é simples (um caractere), fácil de ler (seu olho não se distrai com outros caracteres principais) e evita com êxito colisões de nomes com variáveis ​​no nível do procedimento e propriedades no nível da classe. . Eu recomendo o sublinhado principal para todos os idiomas que o suportam. Se eu quiser que minha classe seja totalmente compatível com CLS, poderia deixar de fora o prefixo em qualquer variável de membro protegida por C #. Na prática, no entanto, nunca me preocupo com isso, pois mantenho todas as variáveis ​​de membro potencialmente protegidas privadas e forneço acessores e mutadores protegidos. Por que: Em poucas palavras, esta convenção é simples (um caractere), fácil de ler (seu olho não se distrai com outros caracteres principais) e evita com êxito colisões de nomes com variáveis ​​no nível do procedimento e propriedades no nível da classe. . Eu recomendo o sublinhado principal para todos os idiomas que o suportam. Se eu quiser que minha classe seja totalmente compatível com CLS, posso deixar o prefixo em qualquer variável de membro protegida por C #. Na prática, no entanto, nunca me preocupo com isso, pois mantenho todas as variáveis ​​de membro potencialmente protegidas privadas e forneço acessores e mutadores protegidos. Por que: Em poucas palavras, esta convenção é simples (um caractere), fácil de ler (seu olho não se distrai com outros caracteres principais) e evita com êxito colisões de nomes com variáveis ​​no nível do procedimento e propriedades no nível da classe. . Eu nunca me preocupo com isso, pois mantenho todas as variáveis ​​de membro potencialmente protegidas privadas e, ao invés disso, forneço acessores e mutadores protegidos. Por que: Em poucas palavras, esta convenção é simples (um caractere), fácil de ler (seu olho não se distrai com outros caracteres principais) e evita com êxito colisões de nomes com variáveis ​​no nível do procedimento e propriedades no nível da classe. . Eu nunca me preocupo com isso, pois mantenho todas as variáveis ​​de membro potencialmente protegidas privadas e, ao invés disso, forneço acessores e mutadores protegidos. Por que: Em poucas palavras, esta convenção é simples (um caractere), fácil de ler (seu olho não se distrai com outros caracteres principais) e evita com êxito colisões de nomes com variáveis ​​no nível do procedimento e propriedades no nível da classe. .


6

O primeiro comentarista (R Samuel Klatchko) referenciou: Quais são as regras sobre o uso de sublinhado em um identificador C ++? que responde à pergunta sobre o sublinhado em C ++. Em geral, você não deve usar um sublinhado à esquerda, pois ele é reservado para o implementador do seu compilador. O código com o qual você está vendo _varprovavelmente é um código herdado ou escrito por alguém que cresceu usando o antigo sistema de nomes que não desaprovava os sublinhados principais.

Como outras respostas indicam, ele costumava ser usado em C ++ para identificar variáveis ​​de membros da classe. No entanto, não tem significado especial no que diz respeito aos decoradores ou sintaxe. Então, se você quiser usá-lo, ele será compilado.

Vou deixar a discussão em C # para outras pessoas.


5

_var não tem significado e serve apenas para facilitar a distinção de que a variável é uma variável de membro privado.

No C ++, o uso da convenção _var é uma forma incorreta, porque existem regras que regem o uso do sublinhado na frente de um identificador. _var é reservado como um identificador global, enquanto _Var (sublinhado + letra maiúscula) é reservado a qualquer momento. É por isso que em C ++, você verá pessoas usando a convenção var_.


4

Você pode criar suas próprias diretrizes de codificação. Basta escrever uma documentação clara para o resto da equipe.

Usar _field ajuda o Intelilsense a filtrar todas as variáveis ​​de classe apenas digitando _.

Eu geralmente sigo as Diretrizes de Brad Adams , mas recomenda não usar sublinhado.


2

O padrão de nomeação Microsoft para C # diz variáveis e parâmetros devem usar o formulário caso camelo menor IE: paramName . A norma também exige campos a seguir a mesma forma, mas isso pode levar a código claro tantas equipes pedir um prefixo sublinhado para melhorar a clareza IE: _fieldName .


2

Com o C #, as Diretrizes de Design do Microsoft Framework sugerem não usar o caractere sublinhado para membros públicos . Para membros privados , sublinhados podem ser usados. De fato, Jeffrey Richter (frequentemente citado nas diretrizes) usa um m_ por exemplo e um "s_" para membros estáticos privados.

Pessoalmente, uso apenas _ para marcar meus membros particulares. "m_" e "s_" se aproximam da notação húngara, que não é apenas desaprovada no .NET, mas pode ser bastante detalhada e acho que aulas com muitos membros são difíceis de fazer uma rápida verificação alfabética dos olhos (imagine 10 variáveis, todas começando com m_) .


Como a notação húngara indica tipo, não acho que você possa realmente dizer que m / s está próximo disso.
Jerry Nixon

@ JerryNixon-MSFT Identificamos o tipo de dados variável e o tipo de visibilidade variável como a mesma coisa quando se trata da noção húngara?
Necro

1

Eu uso a nomeação _var para variáveis ​​de membro de minhas classes. Existem 2 razões principais que eu faço:

1) Isso me ajuda a acompanhar as variáveis ​​de classe e as funções locais quando leio meu código mais tarde.

2) Ajuda no Intellisense (ou outro sistema de conclusão de código) quando estou procurando uma variável de classe. Apenas conhecer o primeiro caractere é útil para filtrar a lista de variáveis ​​e métodos disponíveis.


1
É um aborrecimento em um método maior contar com o hover intellisense ou a varredura para ver se uma var é definida localmente ou não. Também prefira "__" para estática pelos mesmos motivos que você mencionou, mas atualmente está desfavorecido.
26413 crokusek

1

No que diz respeito às linguagens C e C ++, não há significado especial para um sublinhado no nome (início, meio ou fim). É apenas um caractere de nome de variável válido. As "convenções" vêm de práticas de codificação dentro de uma comunidade de codificação.

Como já indicado por vários exemplos acima, _ no início pode significar membros privados ou protegidos de uma classe em C ++.

Deixe-me contar uma história que pode ser divertida. No UNIX, se você possui uma função principal da biblioteca C e um back-end do kernel em que deseja expor a função do kernel ao espaço do usuário, o _ fica preso na frente do stub da função que chama a função do kernel diretamente sem fazer mais nada. O exemplo mais famoso e familiar disso é exit () vs _exit () nos kernels do tipo BSD e SysV: Lá, exit () faz coisas no espaço do usuário antes de chamar o serviço de saída do kernel, enquanto _exit apenas mapeia para o serviço de saída do kernel.

Então _ foi usado para coisas "locais", neste caso local sendo local da máquina. Normalmente _functions () não eram portáteis. Nesse sentido, você não deve esperar o mesmo comportamento em várias plataformas.

Agora, como _ nos nomes de variáveis, como

int _foo;

Bem, psicologicamente, um _ é uma coisa estranha a ser digitada no começo. Portanto, se você deseja criar um nome de variável que tenha menos chances de entrar em conflito com outra coisa, ESPECIALMENTE ao lidar com substituições de pré-processador, você deve considerar o uso de _.

Meu conselho básico seria seguir sempre a convenção da sua comunidade de codificação, para que você possa colaborar com mais eficiência.


0

Simplesmente significa que é um campo de membro da classe.


0

Não existe uma convenção de nomeação única em particular, mas já vi isso para membros particulares.


0

Muitas pessoas gostam de ter campos particulares com um sublinhado. É apenas uma convenção de nomenclatura.

As convenções de nomenclatura 'oficiais' do C # prescrevem nomes minúsculos simples (sem sublinhado) para campos particulares.

Não conheço as convenções padrão para C ++, embora os sublinhados sejam amplamente utilizados.


0

É apenas uma convenção que alguns programadores usam para deixar claro quando você está manipulando um membro da classe ou algum outro tipo de variável (parâmetros, local para a função, etc.). Outra convenção que também é amplamente utilizada para variáveis-membro é prefixar o nome com 'm_'.

De qualquer forma, essas são apenas convenções e você não encontrará uma única fonte para todas elas. Eles são uma questão de estilo e cada equipe, projeto ou empresa de programação tem o seu (ou até não o tem).


0

Há uma razão totalmente legítima para usá-lo em C #: se o código também deve ser extensível a partir do VB.NET. (Caso contrário, eu não faria.)

Como o VB.NET não diferencia maiúsculas de minúsculas, não há uma maneira simples de acessar o fieldmembro protegido neste código:

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

Por exemplo, isso acessará o getter de propriedades, não o campo:

Public Class VBClass
    Inherits CSharpClass

    Function Test() As Integer
        Return Field
    End Function

End Class

Caramba, eu nem consigo escrever fieldem letras minúsculas - o VS 2010 continua corrigindo isso.

Para torná-lo facilmente acessível para classes derivadas no VB.NET, é necessário criar outra convenção de nomenclatura. Prefixar um sublinhado é provavelmente o menos intrusivo e o mais "historicamente aceito" deles.


0

Agora, a notação usando "this" como neste.foobarbaz é aceitável para variáveis ​​de membro da classe C #. Ele substitui a antiga "m_" ou apenas a notação "__". Isso torna o código mais legível, porque não há dúvida do que está sendo referência.


0

Pela minha experiência (certamente limitada), um sublinhado indicará que é uma variável de membro privado. Como Gollum disse, isso vai depender da equipe, no entanto.


0

Pergunta antiga, nova resposta (C #).

Outro uso de sublinhados para C # é o DI (injeção de dependência) do ASP NET Core. readonlyVariáveis privadas de uma classe que foram atribuídas à interface injetada durante a construção devem começar com um sublinhado. Eu acho que é um debate se usar sublinhado para todos os membros privados de uma classe (embora a própria Microsoft o siga), mas este é certo.

private readonly ILogger<MyDependency> _logger;

public MyDependency(ILogger<MyDependency> logger)
{
    _logger = logger;
}

-2

Uma convenção de nomenclatura como essa é útil quando você está lendo um código, principalmente um código que não é seu. Uma convenção de nomenclatura forte ajuda a indicar onde um membro específico é definido, que tipo de membro é etc. A maioria das equipes de desenvolvimento adota uma convenção de nomenclatura simples e simplesmente prefixa os campos dos membros com um sublinhado ( _fieldName). No passado, eu usei a seguinte convenção de nomenclatura para C # (que é baseada nas convenções da Microsofts para o código de estrutura .NET, que pode ser visto no Reflector):

Campo da instância: m_fieldName
Campo estático: s_fieldName Membro
público / protegido / interno: PascalCasedName ()
Membro privado: camelCasedName ()

Isso ajuda as pessoas a entender a estrutura, o uso, a acessibilidade e a localização dos membros ao ler códigos desconhecidos muito rapidamente.


3
Na verdade, a Microsoft não recomenda o uso de prefixos m_, s_. Não use um prefixo para nomes de campos. Por exemplo, não use g_ ou s_ para distinguir campos estáticos e não estáticos. msdn.microsoft.com/en-us/library/ms229012.aspx
Zied

1
Como eu disse, dê uma olhada no código fonte com o Reflector. Você ficará surpreso com o quanto eles fogem de suas próprias recomendações. ;) Como minha postagem mencionou, ela ajuda a melhorar a legibilidade do seu código, e minha última equipe realmente gostou da convenção de nomes listada acima.
jrista
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.