Convención de nomenclatura: subrayado en variables C ++ y C #

146

Es común ver un _varnombre de variable en un campo de clase. ¿Qué significa el guión bajo? ¿Hay alguna referencia para todas estas convenciones de nombres especiales?

Stan
fuente
17
Algunas pautas de codificación corporativa erróneas sugieren agregar verrugas a las variables miembro para distinguirlas de las variables locales, por la creencia de que las clases y las funciones inevitablemente crecerán tanto que no se puede hacer un seguimiento de lo que ocurre sin pistas vagas como esta. Las personas que sugieren tales convenciones son con demasiada frecuencia aquellas cuyo código más las necesita.
Mike Seymour
26
@ Mike: tu declaración general no es cierta. Descubrí que usar esta convención hace que sea mucho más fácil escanear métodos rápidamente y obtener una buena comprensión de la clase.
ChaosPandion
12
@ChaosPandion: luego no lo lea como una declaración general. "Algunos" no significa "todos", y "con demasiada frecuencia" no significa "siempre", y tal vez usted sea una excepción a mi experiencia.
Mike Seymour
17
En C ++, evite los guiones bajos. En muchos contextos (es decir, en el ámbito global, cuando sigue una letra mayúscula, etc.) están reservados para la implementación, y en realidad se arriesga a que algunos macro pisoteen sobre ellos. Entonces, si los quieres, hazlos subrayados .
sbi

Respuestas:

120

El guión bajo es simplemente una convención; nada mas. Como tal, su uso siempre es algo diferente para cada persona. Así es como los entiendo para los dos idiomas en cuestión:

En C ++, un guión bajo generalmente indica una variable miembro privada.

En C #, generalmente veo que se usa solo cuando se define la variable de miembro privado subyacente para una propiedad pública. Otras variables de miembros privados no tendrían un guión bajo. Sin embargo, este uso se ha desvanecido con el advenimiento de las propiedades automáticas.

Antes de:

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

Después:

public string Name { get; set; }
jdmichal
fuente
11
Excepto para los equipos que desean que sus propiedades sean inmutables.
ChaosPandion
11
Los identificadores que comienzan con guiones bajos están reservados para el compilador. El uso de guiones bajos de prefijo puede entrar en conflicto con los símbolos del compilador.
Thomas Matthews
12
@Thomas Matthews - no en C #.
EMP
11
@ChaosPandion Supongo que lo que quieres decir con "inmutable" es en realidad "solo lectura", en cuyo caso se puede usar public string Name { get; private set; }. Es cierto que no es perfectamente inmutable, pero está ahí.
jdmichal
77
@Thomas En un contexto de clase, los identificadores que comienzan con guiones bajos seguidos de una letra mayúscula se reservan en C ++. _varNo esta reservado.
Tyler McHenry el
84

Es una buena práctica NO usar UNDERSCORES antes de cualquier nombre de variable o nombre de parámetro en C ++

Los nombres que comienzan con un guión bajo o un guión bajo doble están RESERVADOS para los implementadores de C ++. Los nombres con un guión bajo están reservados para que la biblioteca funcione.

Si tiene una lectura en el Estándar de codificación C ++, verá que en la primera página dice:

"No sobrelegislate los nombres, pero use una convención de nomenclatura consistente: solo hay dos cosas que debe hacer: a) nunca use" nombres poco claros ", los que comienzan con un guión bajo o que contienen un guión bajo doble"; (p2, estándares de codificación C ++, Herb Sutter y Andrei Alexandrescu)

Más específicamente, el borrador de trabajo de ISO establece las reglas reales:

Además, algunos identificadores están reservados para su uso en implementaciones de C ++ y no se utilizarán de otra manera; No se requiere diagnóstico. (a) Cada identificador que contenga un guión bajo doble __ o comience con un guión bajo seguido de una letra mayúscula está reservado a la implementación para cualquier uso. (b) Cada identificador que comienza con un guión bajo está reservado a la implementación para su uso como nombre en el espacio de nombres global.

Es una buena práctica evitar comenzar un símbolo con un guión bajo en caso de que accidentalmente pase por una de las limitaciones anteriores.

Puede verlo usted mismo por qué el uso de guiones bajos puede ser desastroso al desarrollar un software:

Intente compilar un programa simple helloWorld.cpp como este:

g++ -E helloWorld.cpp

Verá todo lo que sucede en el fondo. Aquí hay un fragmento:

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

¡Puedes ver cuántos nombres comienzan con doble guión bajo!

Además, si observa las funciones de miembros virtuales, verá que * _vptr es el puntero generado para la tabla virtual que se crea automáticamente cuando utiliza una o más funciones de miembros virtuales en su clase. Pero esa es otra historia ...

Si usa guiones bajos, podría tener problemas de conflicto y NO TENDRÁ IDEA lo que lo está causando, hasta que sea demasiado tarde.

Constantinos Glynos
fuente
44
¿No son los nombres que no son globales o de alcance de archivo y comienzan con guión bajo y una letra minúscula perfectamente bien? Hago esto todo el tiempo porque es muy limpio para casos específicos, por ejemplo: void A :: set_size (int _size) {size = _size; }. ¿Qué haces para usos triviales como este?
tukra
3
El guión bajo seguido de una letra minúscula está permitido en un alcance no global / de archivo, creo. ¿Me puede mostrar en qué parte del estándar dice que no lo es? El problema con el subrayado final es que ya lo uso para los miembros variables a veces. Entonces podría tener la función 'int size ();' miembro var 'int size_;' y argumento 'int _size'. Esto tiende a cubrir las cosas muy bien y no he visto mejores alternativas. Funcs en mayúscula no es posible para los genéricos que funcionan con STL. El estilo 'this.size' que gusta a la gente de C # me parece propenso a errores a menos que siempre lo use para el acceso de miembros, lo cual es feo.
tukra
77
Entiendo que algunas personas no desean usar guiones bajos y letras minúsculas porque pueden tener problemas para mantener claro lo que es legal. El estándar C ++ lo permite incluso si algunos autores recomiendan no usarlo. Para mí, dado que es completamente legal y no está reservado, no veo ninguna razón para considerarlo riesgoso. Gracias por sus comentarios.
tukra
3
@tukra: No es completamente legal. El estándar C ++ solo le permite usar un solo guión bajo seguido de una letra minúscula en el ámbito local. ¡Buena suerte! :-)
Constantinos Glynos
44
Lo siento. Pensé que ya habíamos pasado la necesidad de repetir las calificaciones. Se permite un identificador C ++ que comience con un guión bajo seguido de una letra minúscula en todos los ámbitos que no sean el alcance del archivo. Es seguro y legal en funciones, prototipos de funciones, clases, estructuras, uniones, enumeraciones y todo lo que ponga en un espacio de nombres. Si sigue la práctica común de poner todo su código en espacios de nombres, entonces está completamente seguro.
tukra
45

En realidad, la _varconvención proviene de VB, no de C # o C ++ (m _, ... es otra cosa).

Esto llegó a superar la insensibilidad de VB al declarar Propiedades.

Por ejemplo, dicho código no es posible en VB porque lo considera usery Usercomo el mismo 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

Entonces, para superar esto, algunos usaron una convención para agregar '_' al campo privado para venir así

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

Dado que muchas convenciones son para .Net y para mantener cierta uniformidad entre las convenciones de C # y VB.NET, están utilizando la misma.

Encontré la referencia de lo que estaba diciendo: http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices

Estuche Camel con guión bajo destacado. En VB.NET, siempre indique "Protegido" o "Privado", no use "Dim". Se desaconseja el uso de "m_", al igual que el uso de un nombre de variable que difiere de la propiedad por un solo caso, especialmente con variables protegidas, ya que viola el cumplimiento y hará que su vida sea difícil si programa en VB.NET, ya que tendría que nombrar a sus miembros como algo diferente de las propiedades de acceso / mutador. De todos los elementos aquí, el guión bajo principal es realmente el único controvertido. Personalmente, prefiero el caso de camello directo sin guión bajo para mis variables privadas, de modo que no tenga que calificar los nombres de variables con "esto". para distinguir de los parámetros en los constructores o en otros lugares donde probablemente tenga una colisión de nombres. Con la insensibilidad a mayúsculas y minúsculas de VB.NET, esto es aún más importante ya que sus propiedades de acceso generalmente tendrán el mismo nombre que sus variables de miembro privadas, excepto el guión bajo. En lo que respecta a m_, en realidad se trata solo de estética. Yo (y muchos otros) encuentro m_ feo, ya que parece que hay un agujero en el nombre de la variable. Es casi ofensivo. Solía ​​usarlo en VB6 todo el tiempo, pero eso fue solo porque las variables no podían tener un guión bajo destacado. No podría estar más feliz de verlo desaparecer. Microsoft recomienda contra m_ (y la recta _) a pesar de que hicieron ambas cosas en su código. Además, el prefijo con una "m" recta es correcto. Por supuesto, dado que codifican principalmente en C #, pueden tener miembros privados que difieren solo en el caso de las propiedades. La gente de VB tiene que hacer otra cosa. En lugar de tratar de encontrar casos especiales de idioma por idioma, recomiendo el subrayado líder para todos los idiomas que lo admitirán. Si quiero que mi clase sea totalmente compatible con CLS, podría dejar el prefijo en cualquier variable miembro protegida de C #. En la práctica, sin embargo, nunca me preocupo por esto, ya que mantengo privadas todas las variables miembro potencialmente protegidas y en su lugar proporciono accesores y mutadores protegidos. Por qué: en pocas palabras, esta convención es simple (un carácter), fácil de leer (su ojo no se distrae con otros personajes principales) y evita con éxito nombrar colisiones con variables de nivel de procedimiento y propiedades de nivel de clase. . Recomiendo el guión bajo principal para todos los idiomas que lo admitirán. Si quiero que mi clase sea totalmente compatible con CLS, podría dejar el prefijo en cualquier variable miembro protegida de C #. En la práctica, sin embargo, nunca me preocupo por esto, ya que mantengo privadas todas las variables miembro potencialmente protegidas y en su lugar proporciono accesores y mutadores protegidos. Por qué: en pocas palabras, esta convención es simple (un carácter), fácil de leer (su ojo no se distrae con otros personajes principales) y evita con éxito nombrar colisiones con variables de nivel de procedimiento y propiedades de nivel de clase. . Recomiendo el guión bajo principal para todos los idiomas que lo admitirán. Si quiero que mi clase sea totalmente compatible con CLS, podría dejar el prefijo en cualquier variable miembro protegida de C #. En la práctica, sin embargo, nunca me preocupo por esto, ya que mantengo privadas todas las variables miembro potencialmente protegidas y en su lugar proporciono accesores y mutadores protegidos. Por qué: en pocas palabras, esta convención es simple (un carácter), fácil de leer (su ojo no se distrae con otros personajes principales) y evita con éxito nombrar colisiones con variables de nivel de procedimiento y propiedades de nivel de clase. . Nunca me preocupo por esto, ya que mantengo privadas todas las variables miembro potencialmente protegidas y, en su lugar, proporciono accesores y mutadores protegidos. Por qué: en pocas palabras, esta convención es simple (un carácter), fácil de leer (su ojo no se distrae con otros personajes principales) y evita con éxito nombrar colisiones con variables de nivel de procedimiento y propiedades de nivel de clase. . Nunca me preocupo por esto, ya que mantengo privadas todas las variables miembro potencialmente protegidas y, en su lugar, proporciono accesores y mutadores protegidos. Por qué: en pocas palabras, esta convención es simple (un carácter), fácil de leer (su ojo no se distrae con otros personajes principales) y evita con éxito nombrar colisiones con variables de nivel de procedimiento y propiedades de nivel de clase. .

Zied
fuente
6

El primer comentarista (R Samuel Klatchko) hizo referencia: ¿Cuáles son las reglas sobre el uso de un guión bajo en un identificador de C ++? que responde la pregunta sobre el guión bajo en C ++. En general, no debe utilizar un guión bajo, ya que está reservado para el implementador de su compilador. El código con el que está viendo _varprobablemente sea un código heredado o un código escrito por alguien que creció utilizando el antiguo sistema de nombres que no desaprobaba los guiones bajos.

Como dicen otras respuestas, solía usarse en C ++ para identificar variables de miembros de clase. Sin embargo, no tiene un significado especial en cuanto a decoradores o sintaxis. Entonces, si quieres usarlo, se compilará.

Dejaré la discusión de C # a otros.

bsruth
fuente
5

_var no tiene significado y solo sirve para facilitar la distinción de que la variable es una variable miembro privada.

En C ++, usar la convención _var es una mala forma, porque hay reglas que rigen el uso del guión bajo delante de un identificador. _var está reservado como un identificador global, mientras que _Var (guión bajo + mayúscula) está reservado en cualquier momento. Esta es la razón por la cual en C ++, verá personas que usan la convención var_ en su lugar.

5ound
fuente
4

Puede crear sus propias pautas de codificación. Simplemente escriba una documentación clara para el resto del equipo.

Usar _field ayuda a Intelilsense a filtrar todas las variables de clase simplemente escribiendo _.

Por lo general, sigo las pautas de Brad Adams , pero recomienda no usar guiones bajos.

Tony Alexander Hild
fuente
2

La denominación estándar de Microsoft para C # dice variables y parámetros deben utilizar el formulario caso de camellos menor IE: paramName . La norma también exige a los campos siguen la misma forma, pero esto puede llevar a código claro tantos equipos requieren un prefijo de subrayado para mejorar la claridad IE: _fieldName .

ChaosPandion
fuente
2

Con C #, las Directrices de diseño de Microsoft Framework sugieren no utilizar el carácter de subrayado para los miembros públicos . Para miembros privados , se pueden usar guiones bajos. De hecho, Jeffrey Richter (a menudo citado en las pautas) usa una m_ por ejemplo y una "s_" para miembros estáticos privados.

Personalmente, uso solo _ para marcar a mis miembros privados. "m_" y "s_" rayan en la notación húngara, que no solo está mal vista en .NET, sino que puede ser bastante detallada y encuentro que las clases con muchos miembros son difíciles de realizar un escaneo rápido alfabético (imagínese 10 variables, todas comenzando con m_) .

P.Brian.Mackey
fuente
Dado que la notación húngara indica tipo, no creo que realmente se pueda decir que m / s está al borde de ello.
Jerry Nixon
@ JerryNixon-MSFT ¿Identificamos el tipo de datos variables y el tipo de visibilidad variable como lo mismo cuando se trata de la noción húngara?
Necro
1

Uso el nombre _var para las variables miembro de mis clases. Hay 2 razones principales que hago:

1) Me ayuda a hacer un seguimiento de las variables de clase y las variables de función local cuando leo mi código más tarde.

2) Ayuda en Intellisense (u otro sistema de finalización de código) cuando busco una variable de clase. El simple hecho de conocer el primer carácter es útil para filtrar la lista de variables y métodos disponibles.

AJ
fuente
1
Es una molestia en un método más grande confiar en hover intellisense o scan para ver si una var se define localmente o no. También prefiera "__" para las estadísticas por las mismas razones que menciona, pero actualmente no está a favor.
crokusek
1

En lo que respecta a los lenguajes C y C ++, no hay un significado especial para un guión bajo en el nombre (principio, medio o final). Es solo un carácter de nombre de variable válido. Las "convenciones" provienen de las prácticas de codificación dentro de una comunidad de codificación.

Como ya se indicó en varios ejemplos anteriores, _ al principio puede significar miembros privados o protegidos de una clase en C ++.

Permítanme darles un poco de historia que puede ser una trivia divertida. En UNIX si tiene una función de biblioteca central C y un back-end del núcleo donde desea exponer la función del núcleo al espacio del usuario, también _ está atascado frente al código auxiliar de la función que llama a la función del núcleo directamente sin hacer nada más. El ejemplo más famoso y conocido de esto es exit () vs _exit () bajo los núcleos de tipo BSD y SysV: allí, exit () hace cosas de espacio de usuario antes de llamar al servicio de salida del kernel, mientras que _exit solo se asigna al servicio de salida del kernel.

Así que _ se usaba para cosas "locales" en este caso local como máquina local. Por lo general, _functions () no eran portátiles. En eso no debe esperar el mismo comportamiento en varias plataformas.

Ahora como para _ en nombres de variables, como

int _foo;

Bien psicológicamente, un _ es algo extraño tener que escribir al principio. Entonces, si desea crear un nombre de variable que tenga una menor probabilidad de un choque con otra cosa, ESPECIALMENTE cuando se trata de sustituciones preprocesador que desea, considere los usos de _.

Mi consejo básico sería seguir siempre la convención de su comunidad de codificación, para que pueda colaborar de manera más efectiva.

Rey elfo
fuente
0

Simplemente significa que es un campo miembro en la clase.

hkon
fuente
0

No existe una convención de nomenclatura particular, pero la he visto para miembros privados.

Cade Roux
fuente
0

A muchas personas les gusta tener campos privados con el prefijo de subrayado. Es solo una convención de nombres.

Las convenciones de nomenclatura 'oficiales' de C # prescriben nombres simples en minúsculas (sin subrayado) para los campos privados.

No conozco las convenciones estándar para C ++, aunque los guiones bajos son muy utilizados.

Mau
fuente
0

Es solo una convención que algunos programadores usan para dejar en claro cuando se manipula un miembro de la clase o algún otro tipo de variable (parámetros, locales para la función, etc.). Otra convención que también se usa ampliamente para las variables miembro es prefijar el nombre con 'm_'.

De todos modos, estas son solo convenciones y no encontrará una sola fuente para todas ellas. Son una cuestión de estilo y cada equipo de programación, proyecto o empresa tiene el suyo (o incluso no tiene ninguno).

Goedson
fuente
0

Hay una razón totalmente legítima para usarlo en C #: si el código también debe ser extensible desde VB.NET. (De lo contrario, no lo haría).

Dado que VB.NET no distingue entre mayúsculas y minúsculas, no hay una forma sencilla de acceder al fieldmiembro protegido en este código:

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

Por ejemplo, esto accederá al captador de propiedades, no al campo:

Public Class VBClass
    Inherits CSharpClass

    Function Test() As Integer
        Return Field
    End Function

End Class

Diablos, ni siquiera puedo escribir fielden minúsculas: VS 2010 sigue corrigiéndolo.

Para que sea fácilmente accesible a las clases derivadas en VB.NET, uno tiene que llegar a otra convención de nomenclatura. Prefijar un guión bajo es probablemente el menos intrusivo y el más "históricamente aceptado" de ellos.

Andras Vass
fuente
0

Ahora la notación que usa "this" como en this.foobarbaz es aceptable para las variables miembro de clase C #. Reemplaza la antigua notación "m_" o simplemente "__". Hace que el código sea más legible porque no hay duda de lo que se está haciendo referencia.

ddm
fuente
0

Según mi experiencia (ciertamente limitada), un guión bajo indicará que es una variable miembro privada. Sin embargo, como dijo Gollum, esto dependerá del equipo.

Smashery
fuente
0

Vieja pregunta, nueva respuesta (C #).

Otro uso de guiones bajos para C # es con la DI de ASP NET Core (inyección de dependencia). Las readonlyvariables privadas de una clase que se asignó a la interfaz inyectada durante la construcción deberían comenzar con un guión bajo. Supongo que es un debate si usar subrayado para cada miembro privado de una clase (aunque Microsoft lo sigue), pero este es seguro.

private readonly ILogger<MyDependency> _logger;

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

Una convención de nomenclatura como esta es útil cuando está leyendo código, particularmente código que no es el suyo. Una convención de nomenclatura sólida ayuda a indicar dónde se define un miembro en particular, qué tipo de miembro es, etc. La mayoría de los equipos de desarrollo adoptan una convención de nomenclatura simple y simplemente prefijan los campos de miembros con un guión bajo ( _fieldName). En el pasado, he usado la siguiente convención de nomenclatura para C # (que se basa en las convenciones de Microsofts para el código de marco .NET, que se puede ver con Reflector):

Campo de instancia: m_fieldName
Campo estático: s_fieldName Miembro
público / protegido / interno: PascalCasedName ()
Miembro privado: camelCasedName ()

Esto ayuda a las personas a comprender la estructura, el uso, la accesibilidad y la ubicación de los miembros cuando leen códigos desconocidos muy rápidamente.

jrista
fuente
3
En realidad, Microsoft no recomienda usar prefijos m_, s_. No use un prefijo para los nombres de campo. Por ejemplo, no use g_ o s_ para distinguir los campos estáticos de los no estáticos. msdn.microsoft.com/en-us/library/ms229012.aspx
Zied
1
Como dije, eche un vistazo a su código fuente con Reflector. Te sorprenderá cuánto eluden sus propias recomendaciones. ;) Como mencioné en mi publicación, ayuda a mejorar la legibilidad de su código, y a mi último equipo realmente le gustó la convención de nomenclatura mencionada anteriormente.
jrista