Конвенція іменування - підкреслення в змінних C ++ та C #


146

Загальне бачити _varім'я змінної у полі класу. Що означає підкреслення? Чи є посилання на всі ці спеціальні угоди про іменування?



17
Деякі неправильні вказівки щодо корпоративного кодування пропонують додавати бородавки до змінних членів, щоб відрізнити їх від локальних змінних, з віри, що класи та функції неминуче зростуть настільки роздутими, що ви не можете відслідковувати, що робити без розпливчастих натяків на кшталт цього. Люди, які пропонують такі конвенції, занадто часто є тими, чий код їм найбільше потрібен.
Майк Сеймур

26
@Mike - Ваше твердження про ковдру просто не відповідає дійсності. Я виявив, що використання цієї конвенції значно простіше швидко сканувати методи та добре розуміти клас.
ChaosPandion

12
@ChaosPandion: тоді не читайте це як заготовку. "Деякі" не означають "усі", і "занадто часто" не означають "завжди", і, можливо, ти є винятком з мого досвіду.
Майк Сеймур

17
У C ++ уникайте головних підкреслень. У багатьох контекстах (тобто, в глобальному масштабі, коли йде велика літера тощо), вони зарезервовані для реалізації, і ви насправді ризикуєте мати якийсь макрос натоптати їх. Тож якщо ви хочете їх, зробіть їх підкресленнями .
sbi

Відповіді:


120

Підкреслення - це просто умова; більше нічого. Як таке, його використання завжди дещо різне для кожної людини. Ось як я їх розумію для двох розглянутих мов:

У C ++ підкреслення зазвичай вказує на змінну приватного члена.

У C # я зазвичай бачу, що він використовується лише під час визначення базової змінної приватного члена для публічної власності. Інші змінні приватного члена не мали б підкреслення. Це використання значною мірою пішло убік із появою автоматичних властивостей.

Перед:

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

Після:

public string Name { get; set; }

11
За винятком команд, які хочуть, щоб їх властивості були незмінні.
ChaosPandion

11
Ідентифікатори, що починаються з підкреслення, зарезервовані для компілятора. Використання підкреслень префікса може суперечити символам компілятора.
Томас Меттьюз

12
@Thomas Matthews - не в C #.
EMP

11
@ChaosPandion Я припускаю, що те, що ви маєте на увазі під "непорушним", насправді є "лише для читання", і в цьому випадку ви можете використовувати public string Name { get; private set; }. Щоправда, це не зовсім непорушно, але воно є.
jdmichal

7
@Thomas У контексті класу ідентифікатори, що починаються з підкреслення, після чого велика літера зарезервована у C ++. _varне зарезервовано.
Тайлер Макенрі

84

Найкраще використовувати НЕ використовувати UNDERSCORES перед будь-яким ім'ям змінної або параметром у C ++

Імена, що починаються з підкреслення або подвійного підкреслення, резервовані для реалізаторів C ++. Імена з підкресленням зарезервовані для роботи бібліотеки.

Якщо ви прочитали в стандарті кодування C ++, ви побачите, що на першій сторінці написано:

"Не переборщуйте іменування, але використовуйте послідовну конвенцію про іменування: Є лише два обов'язкові дози: а) ніколи не використовуйте" невмілих імен ", тих, що починаються з підкреслення або містять подвійне підкреслення;" (p2, стандарти кодування C ++, Herb Sutter та Andrei Alexandrescu)

Більш конкретно, робочий проект ISO визначає фактичні правила:

Крім того, деякі ідентифікатори зарезервовані для використання реалізаціями C ++ і не повинні використовуватися інакше; діагностика не потрібна. (a) Кожен ідентифікатор, який містить подвійне підкреслення __ або починається з підкреслення, за яким йде велика літера, зарезервований для реалізації для будь-якого використання. (b) Кожен ідентифікатор, який починається з підкреслення, зарезервований для реалізації для використання в якості імені в глобальному просторі імен.

Найкраще, щоб уникнути запуску символу з підкресленням, якщо ви випадково переходите на одне з вищезазначених обмежень.

Ви самі бачите, чому таке використання підкреслення може бути згубним при розробці програмного забезпечення:

Спробуйте скласти просту програму helloWorld.cpp так:

g++ -E helloWorld.cpp

Ви побачите все, що відбувається на задньому плані. Ось фрагмент:

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

Ви можете бачити, скільки імен починається з подвійного підкреслення!

Крім того, якщо ви подивитеся на функції віртуальних членів, ви побачите, що * _vptr - це покажчик, сформований для віртуальної таблиці, який автоматично створюється, коли ви використовуєте одну або кілька функцій віртуальних членів у своєму класі! Але це вже інша історія ...

Якщо ви використовуєте підкреслення, ви можете потрапити в конфліктні питання, і ви НЕ ВІДБУДЕТЕ ІДЕЇ, що викликає це, поки не пізно.


4
Чи не є імена, які не мають глобального масштабу чи файлу, і починаються з підкреслення та малої літери ідеально? Я роблю це постійно, тому що це дуже чисто для конкретних випадків, наприклад: void A :: set_size (int _size) {size = _size; }. Що ви робите для таких тривіальних вживань?
тукра

3
Підкреслення, що супроводжується нижньою літерою, дозволено в не глобальній / файльній області, я вважаю. Ви можете мені показати, де в стандарті написано, що це не так? Проблема з підкресленням підкреслення полягає в тому, що я вже іноді використовую це для варіантів членів. Тому у мене може бути функція 'int size ();' член var 'int size_;' та аргумент 'int _size'. Це, як правило, добре висвітлює речі, і я не бачив кращих альтернатив. Програми з великою літери не можливі для дженериків, які працюють зі STL. Стиль "this.size", який подобається людям C #, здається мені схильним до помилок, якщо ви завжди не використовуєте його для доступу до членів, який некрасивий.
тукра

7
Я розумію, що деякі люди не хочуть використовувати підкреслення та малі літери, оскільки у них можуть виникнути проблеми з ясуванням того, що є законним. Стандарт C ++ дозволяє це, навіть якщо деякі автори рекомендують не використовувати його. Для мене, оскільки це повністю законно і не зарезервовано, я не бачу причин вважати це ризикованим. Дякуємо за ваш відгук.
тукра

3
@tukra: Це не повністю законно. Стандарт C ++ тільки дозволяє вам використовувати один символ підкреслення , за яким слід малої літери в локальній області видимості. Удачі! :-)
Константінос Глінос

4
Вибачте. Я думав, нам минуле потрібно повторити кваліфікацію. Ідентифікатор C ++, що починається з підкреслення, за яким складається з малої літери, дозволений у будь-якій області, окрім області файлу. Це безпечно і законно в функціях, прототипах функцій, класах, структурах, об'єднаннях, перерахунках і всьому, що ви розміщуєте в просторі імен. Якщо ви дотримуєтесь загальної практики введення всього коду в простори імен, то ви повністю безпечні.
тукра

45

Насправді _var умова походить від VB, а не C # або C ++ (m _, ... інша річ).

Це вдалося подолати нечутливість VB при декларуванні властивостей.

Наприклад, такий код неможливий у VB, оскільки він вважає userі Userтаким самим ідентифікатором

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

Щоб подолати це, деякі використовували конвенцію, щоб додати "_" до приватного поля, щоб прийти таким

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

Оскільки багато конвенцій призначені для .Net і зберігають деяку однаковість між умовами C # et VB.NET, вони використовують ту саму.

Я знайшов посилання на те, що я говорив: http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices

Справа верблюда з провідним підкресленням. У VB.NET завжди вказуйте "Захищений" або "Приватний", не використовуйте "Дім". Використання "m_" не перешкоджає, як і використання імені змінної, яка відрізняється від властивості лише в окремих випадках, особливо із захищеними змінними, що порушує відповідність, і заподіє вашому життю біль, якщо ви програмуєте в VB.NET, як ви повинен був назвати своїх членів чимось відмінним від властивостей аксесуара / мутатора. З усіх пунктів тут, головне підкреслення дійсно єдине спірне. Я особисто віддаю перевагу над прямим випадком верблюда без підкреслень для моїх приватних змінних, так що мені не доведеться кваліфікувати імена змінних з "це". відрізнити від параметрів у конструкторах чи в інших місцях, де я, швидше за все, матимуть зіткнення імен. З нечутливістю випадку VB.NET це ще важливіше, оскільки властивості вашого доступу зазвичай матимуть те саме ім'я, що і ваші змінні приватного члена, за винятком підкреслення. Що стосується m_, то мова йде саме про естетику. Я (та багато інших) вважаю m_ потворним, оскільки, схоже, є ім'я змінної. Це майже образливо. Я використовував його в VB6 весь час, але це було лише тому, що змінні не могли мати провідного підкреслення. Я не міг бути щасливішим, щоб побачити, як це минає. Microsoft рекомендує проти m_ (і прямого _), навіть якщо вони виконували обидва у своєму коді. Також правильно виходить префіксація з прямим "м". Звичайно, оскільки вони кодують в основному на C #, вони можуть мати приватних членів, які відрізняються лише у випадку, коли вони властивості. Люди з VB повинні робити щось інше. Замість того, щоб спробувати і придумати спеціальні випадки мови, мовні, я рекомендую провідне підкреслення для всіх мов, які його підтримують. Якщо я хочу, щоб мій клас був повністю сумісним із CLS, я можу залишити префікс будь-яких змінних C #, що захищаються. На практиці я, однак, ніколи не переживаю з цього приводу, оскільки зберігаю приватні всі потенційно захищені змінні члена, а натомість постачаю захищені аксесуари та мутатори. Чому: у двох словах, ця умова є простою (один символ), легко читається (очі не відволікаються іншими провідними символами) і успішно уникає імен зіткнення зі змінними на рівні процедури та властивостями рівня класу. Властивості рівня класу . Я рекомендую провідне підкреслення для всіх мов, які його підтримують. Якщо я хочу, щоб мій клас був повністю сумісним із CLS, я можу залишити префікс будь-яких змінних C #, що захищаються. На практиці я, однак, ніколи не переживаю з цього приводу, оскільки зберігаю приватні всі потенційно захищені змінні члена, а натомість постачаю захищені аксесуари та мутатори. Чому: у двох словах, ця умова є простою (один символ), легко читається (очі не відволікаються іншими провідними символами) і успішно уникає імен зіткнення зі змінними на рівні процедури та властивостями рівня класу. Властивості рівня класу . Я рекомендую провідне підкреслення для всіх мов, які його підтримують. Якщо я хочу, щоб мій клас був повністю сумісним із CLS, я можу залишити префікс будь-яких змінних C #, що захищаються. На практиці я, однак, ніколи не переживаю з цього приводу, оскільки зберігаю приватні всі потенційно захищені змінні члена, а натомість постачаю захищені аксесуари та мутатори. Чому: у двох словах, ця умова є простою (один символ), легко читається (очі не відволікаються іншими провідними символами) і успішно уникає імен зіткнення зі змінними на рівні процедури та властивостями рівня класу. Властивості рівня класу . Я ніколи не переживаю з цього приводу, оскільки зберігаю приватні всі потенційно захищені змінні члена, а натомість постачаю захищені аксесуари та мутатори. Чому: у двох словах, ця умова є простою (один символ), легко читається (очі не відволікаються іншими провідними символами) і успішно уникає імен зіткнення зі змінними на рівні процедури та властивостями рівня класу. Властивості рівня класу . Я ніколи не переживаю з цього приводу, оскільки зберігаю приватні всі потенційно захищені змінні члена, а натомість постачаю захищені аксесуари та мутатори. Чому: у двох словах, ця умова є простою (один символ), легко читається (очі не відволікаються іншими провідними символами) і успішно уникає імен зіткнення зі змінними на рівні процедури та властивостями рівня класу. Властивості рівня класу .


6

Перший коментатор (Р. Самуель Клачко) згадав: Які правила використання підкреслення в ідентифікаторі C ++? який відповідає на питання про підкреслення в C ++. Загалом, ви не повинні використовувати провідне підкреслення, оскільки це зарезервовано для реалізації вашого компілятора. Код, який ви бачите_var , мабуть, або застарілий код, або код, написаний людиною, яка виросла за допомогою старої системи імен, яка не нахмурилася на провідних підкресленнях.

Як і інші відповіді, він використовувався в C ++ для ідентифікації змінних членів класу. Однак це не має особливого значення, що стосується декораторів чи синтаксису. Тож якщо ви хочете ним скористатися, він складеться.

Я залишу дискусію C # іншим.


5

_var не має значення і служить лише для того, щоб полегшити розрізнення, що змінна є змінною приватного члена.

У C ++ використання конвенту _var є поганою формою, оскільки існують правила, що регулюють використання підкреслення перед ідентифікатором. _var зарезервовано як глобальний ідентифікатор, тоді як _Var (підкреслення + велика літера) зарезервовано будь-коли. Ось чому в C ++ ви побачите людей, які замість цього використовують конвенцію var_.


4

Ви можете створити власні вказівки щодо кодування. Просто напишіть чітку документацію для решти команди.

Використання _field допомагає Intelilsense фільтрувати всі змінні класу, просто набравши _.

Я зазвичай дотримуюсь рекомендацій Бреда Адамса , але рекомендую не використовувати підкреслення.


2

Іменування стандарт Microsoft для C # говорить змінні і параметри повинні використовувати нижню форму верблюд випадку IE: paramName . Стандарт також вимагає поля , щоб слідувати тій же формі , але це може привести до неясного коду так багато команд вимагають підкреслення префікса для поліпшення ясності IE: _fieldName .


2

Що стосується C #, то керівні принципи Microsoft Framework Design рекомендують не використовувати символ підкреслення для публічних членів. Для приватних членів, підкреслення добре використовувати. Насправді, Джеффрі Ріхтер (часто цитується в керівництві), наприклад, використовує m_ і "s_" для приватних статичних членів.

Особисто я використовую просто _ для позначення своїх приватних членів. "m_" та "s_" грань на угорській нотації, яка не тільки нахмурилася в .NET, але може бути досить багатослівною, і мені здається, що класи з багатьма членами складно зробити швидке сканування очей в алфавітному порядку (уявіть 10 змінних, починаючи з m_) .


Оскільки угорська нотація вказує на тип, я не думаю, що ви насправді можете сказати, що m / s межа на ній.
Джеррі Ніксон

@ JerryNixon-MSFT Чи ідентифікуємо змінні типи даних та тип змінної видимості як одне і те ж, що стосується угорського поняття?
Некро

1

Я використовую ім'я _var для змінних членів моїх класів. У мене є дві основні причини:

1) Це допомагає мені відстежувати змінні класу та змінні місцевих функцій, коли я читаю свій код пізніше.

2) Це допомагає в Intellisense (або іншій системі заповнення коду), коли я шукаю змінну класу. Просто знання першого символу корисно для фільтрації через список доступних змінних та методів.


1
У більших методах є клопотання покладатися на інтелігенцію наведення або сканування, щоб перевірити, чи визначений вар локально чи ні. Також віддавайте перевагу "__" для статики з тих самих причин, які ви згадуєте, але наразі це не сприймається.
crokusek

1

Що стосується мов C та C ++, то в імені (початок, середина чи кінець) особливого значення немає. Це просто дійсний символ імені змінної. "Конвенції" походять від практики кодування всередині спільноти кодування.

Як уже вказувалося в різних прикладах вище, _ на початку може означати приватних або захищених членів класу в C ++.

Дозвольте трохи розповісти історію, яка може бути цікавою дрібницею. У UNIX, якщо у вас є функція бібліотеки ядра C та зворотний кінець ядра, де ви хочете піднести функцію ядра до простору користувача, а _ застряг перед заглушкою функції, яка викликає функцію ядра безпосередньо, не роблячи нічого іншого. Найвідоміший і знайомий приклад цього - exit () vs _exit () під ядрами типу BSD та SysV: Там, exit () виконує завдання в просторі користувача перед тим, як викликати службу виходу ядра, тоді як _exit просто відображає службу виходу ядра.

Так _ використовувались для "локальних" речей, у цьому випадку місцеві були машинно-локальними. Зазвичай _functions () не були портативними. При цьому не слід очікувати однакової поведінки на різних платформах.

Тепер, що стосується _ у назвах змінних, таких як

int _foo;

Ну психологічно, _ це дивна річ, яку потрібно набрати на початку. Отже, якщо ви хочете створити ім’я змінної, яке б мало менше шансів зіткнутись із чимось іншим, ОСОБЛИВО, коли ви працюєте із замінами перед процесором, ви хочете розглянути використання _.

Моя основна порада полягає в тому, щоб завжди дотримуватися конвенції вашої спільноти кодування, щоб ви могли ефективніше співпрацювати.


0

Це просто означає, що це поле члена в класі.


0

Немає конкретної конвенції про іменування, але я це бачив для приватних членів.


0

Багатьом людям подобається мати приватні поля з префіксом. Це лише конвенція про іменування.

C # 's' офіційні 'імена конвенцій прописують прості малі імена (без підкреслення) для приватних полів.

Мені невідомі стандартні умови для C ++, хоча підкреслення дуже широко використовуються.


0

Це просто умова, яку використовують деякі програмісти, щоб зрозуміти, коли ви маніпулюєте членом класу чи якоюсь іншою змінною (параметри, локальні для функції тощо). Ще одна умова, яка також широко використовується для змінних членів, - це префіксація імені "m_".

Так чи інакше, це лише конвенції, і ви не знайдете для них жодного джерела. Вони - питання стилю, і кожна команда програмування, проект чи компанія мають своїх (або навіть не мають).


0

Є цілком законний привід використовувати його в C #: якщо код також повинен бути розширюваним з VB.NET. (Інакше я б не став.)

Оскільки VB.NET є нечутливим до регістру, fieldу цьому коді немає простого способу доступу до захищеного члена:

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

Наприклад, це отримає доступ до власника, а не до поля:

Public Class VBClass
    Inherits CSharpClass

    Function Test() As Integer
        Return Field
    End Function

End Class

Чорт забираю, я навіть не можу писати fieldмалою літерою - VS 2010 просто виправляє це.

Для того, щоб зробити його доступним для похідних класів у VB.NET, потрібно придумати ще одну умову іменування. Префіксація підкреслення, мабуть, найменш нав'язлива і найбільш «історично прийнята» з них.


0

Тепер позначення, що використовують "this", як у this.foobarbaz, є прийнятним для змінних членів класу C #. Він замінює старі позначення "m_" або просто "__". Це робить код більш читабельним, оскільки немає сумнівів, на що йдеться.


0

З мого досвіду (безумовно, обмеженого), підкреслення вказуватиме, що це змінна особа-член. Як сказав Голлум, це все ж залежатиме від команди.


0

Старе запитання, нова відповідь (C #).

Ще одне використання підкреслень для C # - це з використанням DI DI ASP NET Core (введення залежності). Приватні readonlyзмінні класу, які присвоюються ін'єктованому інтерфейсу під час побудови, повинні починатися з підкреслення. Я думаю, що це дискусія щодо того, чи використовувати підкреслення для кожного приватного члена класу (хоча сам Microsoft слід за ним), але це точно.

private readonly ILogger<MyDependency> _logger;

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

-2

Конвенція про іменування на зразок цього корисна під час читання коду, особливо коду, який не є вашим власним. Сильна конвенція іменування допомагає вказати, де визначений конкретний член, який він є членом і т. Д. Більшість команд розробників приймають просту конвенцію іменування та просто префіксують поля членів із підкресленням ( _fieldName). Раніше я використовував таку умову іменування для C # (яка заснована на конвенціях Microsofts для рамкового коду .NET, який можна побачити за допомогою Reflector):

Поле екземпляра: m_fieldName
Статичне поле: s_fieldName
Загальнодоступний / захищений / внутрішній член: PascalCasedName ()
Приватний член: camelCasedName ()

Це допомагає людям зрозуміти структуру, використання, доступність та розташування членів під час читання незнайомого коду дуже швидко.


3
Насправді, Microsoft не рекомендує використовувати префікси m_, s_. Не використовуйте префікс для імен полів. Наприклад, не використовуйте g_ або s_ для розрізнення статичних та нестатичних полів. msdn.microsoft.com/en-us/library/ms229012.aspx
Zied

1
Як я вже казав, погляньте на їх вихідний код із Reflector. Ви здивуєтеся, наскільки вони ухиляються від власних рекомендацій. ;) Як згадувалося в моєму дописі, це допомагає поліпшити читабельність вашого коду, і моїй останній команді дуже сподобалась перелічена вище конвенція про іменування.
jrista
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.