Подчеркнуть или не подчеркнуть, вот в чем вопрос


131

Есть ли проблемы с отсутствием префикса для частных полей с подчеркиванием в C #, если двоичная версия будет использоваться другими языками фреймворка? Например, поскольку C # чувствителен к регистру, вы можете вызвать поле «foo» и общедоступное свойство «Foo», и оно будет работать нормально.

Будет ли это иметь какой - либо эффект на регистронезависимом языке, как VB.NET, будет ли какое - либо CLS-соответствие (или другими) проблемами , если имена различимы только кожух?


18
Смысл префикса подчеркивания, BTW, не в том, чтобы решать проблемы с регистром. Это для того, чтобы иметь возможность легко и наглядно отличать поля и локальных жителей при чтении кода. Я буду использовать его как в C #, так и в VB.
— Нил Хьюитт

2
@NeilHewitt: Ну, это также предотвращает конфликт параметров функции с переменными-членами, которые требуют добавления каждого из них с помощью this, что отстой. РЕДАКТИРОВАТЬ: Я только что ответил на комментарий четырехлетней давности ...
— Эд С.

Для ясности официальный стандарт _camelCase(только для чтения) github.com/dotnet/corefx/blob/master/Documentation/…
— Крис Марисич,

Я предпочитаю _camelCase для частных резервных магазинов. то есть: личное поле, в котором хранятся назначенные данные и доступ к ним осуществляется через свойство. Мне не нравятся автоматические свойства, потому что они не могут быть инициализированы известным значением в определении класса, и если мне нужен побочный эффект в установщике, мне нужно явно объявленное резервное хранилище. К сожалению, это исправляется, когда я использую ^ R ^ E в редакторе C #, поэтому мне приходится добавлять его обратно ... каждый раз.
— TomXP411

Ответы:


47

Это не повлияет.

Часть рекомендаций по написанию CLS-совместимых библиотек состоит в том, чтобы НЕ иметь двух общедоступных / защищенных объектов, которые различаются только регистром, например, вы НЕ должны иметь

public void foo() {...}

и

public void Foo() {...}

то, что вы описываете, не является проблемой, потому что частный элемент недоступен для пользователя библиотеки


1
Несмотря на то, что эффекта не будет, это все же соглашение, с которым мне было бы неудобно - поскольку это рецепт путаницы, если они отличаются только по регистру. Слишком легко неправильно прочитать или ввести неправильный текст, если единственной разницей является начальный капитал.
— ChrisA

2
PS Лично я в C # не подчеркиваю. Для меня это личное предпочтение, а не религиозное убеждение
— Binary Worrier

1
Я поступил обоими способами, и я хотел принять решение, раз и навсегда, основываясь на знаниях: P
— TheCodeJunkie

46
Я использую символы подчеркивания. Их легче отличить от аргументов и локальных переменных.
— Ринат Абдуллин

4
Я использую _ только для частных полей, однако у меня почти никогда не бывает частных полей из-за свойства 3.5 auto. Как правило, у меня есть личное поле только в том случае, если я реализую отложенную загрузку для непримитивных типов.
— Крис Марисич

280

ВАЖНОЕ ОБНОВЛЕНИЕ (12 апреля 2016 г.):

Мы обратили внимание на то, что внутренний стандарт команды .NET CoreFX настаивает на использовании символа подчеркивания без объяснения причин. Однако , если мы внимательно посмотрим на правила # 3 становится очевидным , что существует система _, t_, s_префиксов, предполагает , почему _был выбран в первую очередь.

  1. Мы используем _camelCaseвнутренние и частные поля и используем только чтение там, где это возможно. Префикс полей экземпляра с _, статические поля с s_и поток статических полей с t_. При использовании в статических полях readonlyдолжен стоять после static(т. Е. static readonlyНет readonly static).
  2. Мы избегаем без this.крайней необходимости.

Итак, если вы, как команда .NET CoreFX, работаете над некоторым критически важным для производительности многопоточным кодом системного уровня , то НАСТОЯТЕЛЬНО РЕКОМЕНДУЕТСЯ:

  • придерживаться своих стандартов кодирования и
  • используйте нижнее подчеркивание и
  • не читайте этот ответ дальше

В противном случае читайте дальше ...

ОРИГИНАЛЬНЫЙ ОТВЕТ:

Давайте сначала договоримся о том, о чем мы говорим. Вопрос в том, как мы получаем доступ к членам экземпляра из нестатических методов и конструкторов класса / подклассов, если модификаторы видимости позволяют это сделать.

Подчеркивание-обозначение

  • предлагает использовать префикс "_" в именах закрытых полей
  • он также говорит, что вы никогда не должны использовать "this", если это абсолютно необходимо.

Это-обозначение

  • предлагает вам просто всегда использовать «это». для доступа к любому члену экземпляра

Почему существует это обозначение?

Потому что это то, как ты

  • отличить параметр от поля, если у них одно и то же имя
  • убедитесь, что вы работаете в контексте текущего экземпляра

пример

public class Demo
{
   private String name;
   public Demo(String name) {
       this.name = name;
   }
}

Почему существует символ подчеркивания?

Некоторым людям не нравится печатать «это», но им все равно нужен способ различать поле и параметр, поэтому они согласились использовать «_» перед полем.

пример

public class Demo
{
   private String _name;
   public Demo(String name) {
      _name = name;
   }
}

Можно подумать, что дело в личном вкусе, и оба варианта одинаково хороши или плохи. Однако есть определенные аспекты, в которых эта нотация превосходит нотацию подчеркивания:

ясность

  • символы подчеркивания заглушают имена
  • this-notation сохраняет имена нетронутыми

Познавательная нагрузка

  • нотация подчеркивания непоследовательна, она заставляет вас обращаться с полями особым образом, но вы не можете использовать ее с другими членами, каждый раз, когда вам нужно спрашивать себя, нужно ли вам свойство или поле

  • эта-нотация согласована, вам не нужно думать, вы просто всегда используете "this" для обозначения любого члена

ОБНОВЛЕНИЕ: как было указано, следующее не является преимуществом

Обслуживание

  • нотация подчеркивания требует, чтобы вы внимательно следили за _рефакторингом, например, превращая поле в свойство (удалить _) или наоборот (добавить _)

  • this-notation не имеет такой проблемы

Автозаполнение

Когда вам нужно увидеть список членов экземпляра:

  • нотация подчеркивания не очень помогает, потому что, когда вы набираете "_", всплывающее окно автозаполнения показывает вам частные поля и все типы, доступные из связанных сборок, смешанные с остальными членами экземпляра
  • this-notation дает вам четкий ответ, набрав "this", вы видите только список участников и ничего больше

неоднозначность

Иногда приходится иметь дело с кодом без помощи Intellisense. Например, когда вы проводите обзор кода или просматриваете исходный код в Интернете.

  • нотация подчеркивания неоднозначна: когда вы видите Something.SomethingElse, вы не можете определить, является ли Something классом, а SomethingElse - его статическим свойством ... или, может быть, Something является свойством текущего экземпляра, которое имеет собственное свойство SomethingElse

  • Эта нотация ясна: когда вы видите Something.SomethingElse, это может означать только класс со статическим свойством, и когда вы видите this.Something.SomethingElse, вы знаете, что Something является членом, а SomethingElse - его свойством

Методы расширения

Вы не можете использовать методы расширения в самом экземпляре, не используя this.

  • нотация подчеркивания требует, чтобы вы не использовали "this", однако с методами расширения вы должны
  • Эта-нотация избавляет вас от колебаний, вы всегда используете «это», точка.

Поддержка Visual Studio

  • нотация подчеркивания не имеет встроенной поддержки в Visual Studio
  • Эта нотация, естественно, поддерживается Visual Studio:

    1. "Это." Квалификация : предпочитать предварять все нестатические поля, используемые в нестатических методах, this.в C #.

Официальные рекомендации

Существует множество официальных правил, в которых четко сказано «не использовать символы подчеркивания», особенно в C #.


22
Это потрясающий ответ. Спасибо, что нашли время собрать всю эту информацию.
— Тигран

5
Не исходит из C ++, потому что в C ++ зарезервированы идентификаторы, начинающиеся с подчеркивания, для использования языка и стандартной библиотеки.
— Rob G

7
Почему вы различаете критически важный для производительности, многопоточный код системного уровня и другой код? Как использование _camelCaseпоможет мне, если мой код критичен к производительности / системному уровню?
— BornToCode 04

6
Использование подчеркиваний не имеет ничего общего с написанием критически важного для производительности, многопоточного или системного кода. Важна последовательность, а команда CoreFX - это просто команда, которая согласовала конкретное соглашение. Это отличный ответ, подкрепленный очень хорошим анализом, сравнивающим соглашения об именах, но я считаю, что добавленная часть, в которой говорится, что «подчеркивания лучше, потому что команда CoreFX так говорит», действительно снижает его качество.
— Şafak Гур

5
Моя проблема в том, что я понимаю логический вывод. en.wikipedia.org/wiki/Inference Но я понимаю, это не для всех.
— user603563 05

67

Взято из файла справки Microsoft StyleCop:

TypeName: FieldNamesMustNotBeginWithUnderscore

CheckId: SA1309

Причина: имя поля в C # начинается с символа подчеркивания.

Описание правила:

Нарушение этого правила происходит, когда имя поля начинается с символа подчеркивания.

По умолчанию StyleCop запрещает использование символов подчеркивания, m_ и т. Д. Для обозначения полей локального класса в пользу «this». префикс. Преимущество использования this. заключается в том, что он в равной степени применяется ко всем типам элементов, включая методы, свойства и т. д., а не только к полям, благодаря чему все вызовы членов класса мгновенно распознаются, независимо от того, какой редактор используется для просмотра кода. Еще одно преимущество состоит в том, что он позволяет быстро различать члены экземпляра и статические элементы, которые не имеют префикса.

Если имя поля или переменной должно соответствовать имени элемента, связанного с Win32 или COM, и, следовательно, должно начинаться с подчеркивания, поместите поле или переменную в специальный класс NativeMethods. Класс NativeMethods - это любой класс, который содержит имя, оканчивающееся на NativeMethods, и предназначен для использования в качестве заполнителя для Win32 или COM-оболочек. StyleCop проигнорирует это нарушение, если элемент помещен в класс NativeMethods.

Другое описание правила указывает на то, что предпочтительной практикой в ​​дополнение к вышесказанному является начало частных полей строчными буквами, а общедоступных - прописными.

Изменить: в качестве продолжения страница проекта StyleCop находится здесь: https://github.com/DotNetAnalyzers/StyleCopAnalyzers . Прочитав файл справки, вы сможете понять, почему они предлагают различные стилистические правила.


7
В основном это "лучшие практики". Как указано в правиле, префикс с «this» может применяться к любому нестатическому члену, в то время как префикс с чем-либо другим может быть неприменим из-за правил синтаксиса языка. Ключевое слово "this" делает намеченный пункт назначения тривиальным.
— Скотт Дорман

5
Я также предпочитаю предполагаемое в языке решение проблемы («это»), а не искусственные способы ее решения.
— galaktor

10
В том же программном обеспечении есть правило, согласно которому у вас не должно быть двух полей, отличающихся только регистром. Итак, что вы делаете с защищенной переменной, заключенной в публичное свойство?
— Lilith River

5
Моя единственная проблема с `` без подчеркивания '' заключается в том, что при программировании с (веб-формой) или чем-то подобным, использование только `` это '' не помогает мне вообще фильтровать те частные поля, которые я определил, а вместо этого просто дает мне гигантский список из восьми миллионов других свойств, включенных в указанный объект.

14
StyleCop, кажется, говорит, что, если я постоянно использую thisпри обращении к любому члену класса, я могу найти все обращения ко всем членам класса, просто выполнив поиск this. Я не могу с этим поспорить, но я также не могу вспомнить время, когда мне нужно было это сделать. Последнее, что я хочу сделать, это добавить утомления к кодированию и засорять мой код this(который почти венгерским) почти без практической выгоды. Дело в том, что если я смотрю на строку кода, все, что начинается с заглавной буквы или подчеркивания, является членом класса, все нижний регистр - локальным.
— devuxer

27

Поскольку мы говорим о закрытом поле, оно не влияет на пользователя вашего класса.

Но я рекомендую использовать подчеркивание для частного поля, потому что это может облегчить понимание кода, например:

private int foo;
public void SetFoo(int foo)
{
  // you have to prefix the private field with "this."
  this.foo = foo;

  // imagine there's lots of code here,
  // so you can't see the method signature



  // when reading the following code, you can't be sure what foo is
  // is it a private field, or a method-argument (or a local variable)??
  if (foo == x)
  {
    ..
  }
}

В нашей команде мы всегда используем префикс подчеркивания для закрытых полей. Таким образом, при чтении некоторого кода я могу очень легко определить частные поля и отличить их от локальных переменных и аргументов. В некотором смысле подчеркивание можно рассматривать как сокращенную версию слова «это».


14
Ну, я всегда ставлю префикс «это», независимо от того, использую ли я поле, свойство или метод.
— TheCodeJunkie

9
Для меня подчеркивание - это своего рода сокращенное обозначение «этого.».
— M4N

2
В R # совет - не вызывать параметр foo. Почему бы не называть его «значением», если вы знаете, что оно будет использоваться для установки Foo?
— thinkbeforecoding

17
@Martin: Проблема с подчеркиванием как сокращением для «this» заключается в том, что его нельзя обязательно применять ко всем членам класса, в то время как «this» может. Я думаю, что код читается намного проще / чище с ключевым словом this. В вашем примере if (foo == x) всегда будет ссылаться на параметр foo.
— Скотт Дорман,

3
@TheCodeJunkie: В вашем коде полно лишних символов.
— Эд С.

15

После работы в среде, которая с тех пор имела очень специфические и очень бессмысленные правила стиля, я продолжил создавать свой собственный стиль. Это тот тип, который я много раз перебрасывал. Я, наконец, решил, что частные поля всегда будут _field, локальные переменные никогда не будут иметь _ и будут в нижнем регистре, имена переменных для элементов управления будут примерно соответствовать венгерской нотации, а параметры обычно будут верблюжьими.

Я ненавижу this.ключевое слово, которое, на мой взгляд, просто добавляет слишком много шума кода. Мне нравится, что Resharper удаляет лишнее. ключевое слово.

Обновление за 6 лет: я анализировал внутреннее устройство Dictionary<TKey,T>для конкретного использования одновременного доступа и неправильно считал частное поле как локальную переменную. Частные поля определенно не должны совпадать с соглашением об именах, что и локальные переменные. Если бы там было подчеркивание, это было бы невероятно очевидно.


18
thisКлючевое слово гарантируемой ссылка на текущий объект. Вы не получите этого с подчеркиванием. Не надо ненавидеть this.
— Jason S

15
Зачем изобретать «стандарт». 'этот.' сообщает вам, что объект является переменной экземпляра Class. говорит вам, что это класс varible. Все остальное - это переменная стека. Подчеркивание относится к той же кучке плохих идей, где теперь разлагается венгерская нотация.
— Quarkly,

4
@ DRAirey1 слишком легко пропустить это. когда вам это нужно, и вы в конечном итоге делаете странные вещи с состоянием.
— Chris Marisic

3
@ChrisMarisic Вы, конечно, можете высказать свое мнение об использовании _, но не считайте его установленным стандартом, если это явно не так.
— давка

3
Я потерял тебя, когда «я создал свой собственный стиль».
— rory.ap

12

Мне нравится подчеркивание, потому что тогда я могу использовать имя в нижнем регистре в качестве параметров метода, например:

public class Person
{
    string _firstName;

    public MyClass(string firstName)
    {
        _firstName = firstName;
    }

    public string FirstName
    {
        get { return _firstName; }
    }
}

39
публичная строка FirstName {получить; частный набор; }
— jason 05

3
Вы по-прежнему можете использовать строчные буквы в качестве параметра метода, используя thisключевое слово. Создание , что немая точка в продолжающемся и всегда спорный «для подчеркивания или нет»:public MyClass(string firstName){ this.firstName = firstName; }
— mateuscb

5
Это будущее, только сейчас, public string FirstName { get; }и сеттер все еще доступен в конструкторе
— Крис Марисич

В этом примере. thisбудет необходимо только в конструкторе. Нет необходимости использовать его где-либо еще. Так firstNameкак имя поля работает очень хорошо.
— Thomas

9

Мне все еще очень нравится использовать подчеркивания перед частными полями по той причине, о которой упоминал Мартин, а также потому, что частные поля затем будут сортироваться вместе в IntelliSense. И это несмотря на порочность венгерских приставок в целом.

Однако в последнее время я обнаружил, что использование префикса подчеркивания для закрытых членов не одобряется, хотя я не совсем уверен, почему. Может, кто-то еще знает? Это просто принцип префикса? Или было что-то связанное с изменением имен общих типов, которые получают подчеркивание в скомпилированных сборках или что-то в этом роде?


4
Для меня _ загромождает _слова при быстром _сканировании кода, это становится меньше похоже на простое чтение _ и больше _подобно необходимости останавливаться на _every _, чтобы подтвердить это и _сознать, что это _не _не управляющий символ некоторой _sort. Он также нарушает отступы, практически сдвигая первый полезный символ в именах полей на один столбец вправо. Мне вообще не нравится C ++, потому что большинство программистов на C ++ склонны писать невероятно лаконичный и медленный для чтения символьный / машинный код, и я просто предпочитаю не иметь этого в коде C # :)
— Оскар Дювеборн,

23
Для меня это. загромождает this.words, когда быстро this.сканирует код, становится не так, как просто читать this.and this.more this. like to need to stop and this.every this. признать это, и это. понять, что это. Не управляющий символ некоторого this.sort. Я бы предпочел найти случайные _fieldFooили _fieldBarзагромождать использование this.fieldFooили this.fieldBar. Я считаю, что this.префикс гораздо неприятнее, чем подчеркивание в начале.
— AggieEric

Я подумал, что, возможно, это несоответствие в опыте могло быть связано с файловыми системами старой школы или протоколами передачи файлов, в которых не допускались пробелы, что приучало некоторых пользователей видеть подчеркивание как пробелы и, следовательно, не отвлекать их чтение. У меня, с другой стороны, есть проблемы с такими именами файлов, поскольку я всегда использовал пробелы в своих собственных именах файлов с самого начала ...
— Оскар Дювеборн

1
@AggieEric попала в точку. От одного чтения его предложения у меня разболится голова! В течение многих лет я пытался придерживаться рекомендаций РС в этом вопросе, и мне так надоело читать маленькие синие thisсловечки повсюду, что я сразу же принял решение, связанное с гневом ботаника. Теперь я неукоснительно использую thisТОЛЬКО для ссылок на свойства или когда мне нужно явно различать thisи base. Думаю, каждому свое :-)
— Riegardt Steyn

1
Я думаю, это потому, что, в конечном счете, начало чего-либо с символа пунктуации ухудшает читаемость. Кажется, это не всех беспокоит, но мне кажется очень неестественным читать все, что начинается с знаков препинания. Чем больше похож на английский код, тем легче мне его читать. А с современными IDE просто офигительно просто отличить локальных от частных участников, потому что они, скорее всего, будут разных цветов.
— Тим Лонг

5

Рекомендация Style Cop или нет, но копание в .NET Framework показывает частое использование "_" для переменных-членов. Что бы ни рекомендовали создатели Style Cop, это не то, что используют большинство сотрудников MS. :) Так что я буду придерживаться символа подчеркивания. Потому что я лично делаю намного меньше ошибок, используя подчеркивание, чем this (пример: использование varName = varName вместо this.varName = varName, это действительно застряло во мне)


3
Underscore также рекомендуется для руководства по стилю ядра .NET: github.com/dotnet/corefx/wiki/Coding-style
— landoncz

3

Я думаю, что в общем и целом поля уровня класса - это ошибка в конструкции языка. Я бы предпочел, чтобы свойства C # имели собственную локальную область видимости:

public int Foo
{
   private int foo;
   get
   {
      return foo;
   }
   set
   {
      foo = value;
   }
}

Это позволило бы полностью отказаться от использования полей.

Единственный раз, когда я когда-либо префикс закрытого поля с подчеркиванием, - это когда свойство требует отдельного резервного поля. Это также единственный раз, когда я использую частные поля. (И поскольку я никогда не использую защищенные, внутренние или общедоступные поля, это единственный раз, когда я использую период для полей.) Насколько я понимаю, если переменная должна иметь область видимости класса, это свойство класса.


Команда C #, похоже, согласна с вами в новом частном int foo {get; set;} синтаксический сахар.
— Dana

Да, конечно; то, что я здесь описываю, без этого невозможно.
— Роберт Россни

Вы описываете «автоматически реализованные свойства». К сожалению, с Visual Basic.NET здесь фактически используется «скрытая» переменная _prefix за кулисами, т.е. если у вас есть автоматически реализованное свойство «Public Property Foo As Integer», вы НЕ могли бы иметь объявление переменной-члена «Private _foo as Целое число »

Нет, я не описываю автоматически реализуемые свойства, по крайней мере, в моем примере. Я описываю уровень области видимости, которого нет в C # или VB. Очень жаль, что VB выбрал такой тривиальный способ изменить имена полей поддержки. C # достаточно уродлив, чтобы случайно не создать переменную с таким же именем.
— Роберт Россни

3

Обозначение _fieldName для частных полей очень легко сломать . Используя "this." обозначение нарушить невозможно. Как бы вы нарушили обозначение _? Заметим:

private void MyMethod()
{
  int _myInt = 1; 
  return; 
}

Итак, я нарушил ваше соглашение об именах, но оно компилируется. Я бы предпочел иметь а) не венгерское соглашение об именах и б) явное. Я за то, чтобы отказаться от венгерского именования, и это в каком-то смысле подходит. Вместо типа объекта перед именем переменной у вас есть уровень доступа.

Сравните это с Ruby, где имя переменной @my_numberсвязывает имя с областью видимости и не может быть разрушено.

изменить: этот ответ стал отрицательным. Мне все равно, это останется.


11
Вряд ли будет обоснованной критикой соглашения об именах, если заявить, что разработчики могут не следовать ему.
— Роберт Россни

8
Вау, ваше определение «легко сломать» и мое, как бы, полная противоположность. Ваш означает «легко сломать намеренно», в то время как большинство других людей, вероятно, означает «легко сломать случайно ». Я оставлю это в качестве упражнения читателю, чтобы выяснить, какой из них более уместен при написании читаемого кода…
— Конрад Рудольф

6
@Konrad: Вы звучите претенциозно, когда говорите "в качестве упражнения для читателя". Это не учебник по математике.
— jcollum

3
Немного менее негативно :) Хотя мы, возможно, гребем против течения, мне также не нравится соглашение о подчеркивании. На мой взгляд, это ничем не отличается от венгерской нотации и, честно говоря, у меня глаза кровоточат (ухудшает читаемость). Мы отказались от венгерской нотации в C #, и пора избавиться от этого последнего следа недоверия к своей среде IDE.
— Тим Лонг

1
Я слышал, что MS на самом деле говорит, что подчеркивание не должно использоваться в его руководстве по стилю C #. blogs.msdn.microsoft.com/brada/2005/01/26/… - раздел 2.6 - похоже, Брэд Абрамс, по крайней мере, с нами согласен!
— jcollum 05

1

Если вы хотите, чтобы ваша сборка была CLS-совместимой, вы можете использовать атрибут CLSCompliant в вашем файле assemblyinfo. Затем компилятор будет жаловаться, если ваш код содержит материал, который не соответствует требованиям cls.

Затем, если у вас есть 2 свойства, которые различаются только регистром, компилятор выдаст ошибку. С другой стороны, когда у вас есть частное поле и общедоступное свойство в одном классе, проблем не возникнет.

(Но я также всегда ставлю перед своими закрытыми членами знак подчеркивания. Это также помогает мне, когда я читаю свой код, ясно давать понять, что определенная переменная является полем члена).


0

Мне нравится использовать подчеркивание перед личными полями по двум причинам. Об одном уже упоминалось, поля выделяются среди связанных с ними свойств в коде и в Intellisense. Вторая причина в том, что я могу использовать одни и те же соглашения об именах независимо от того, кодирую ли я на VB или C #.


1
ого, это мудро? Разве подчеркивание не означает «продолжается на следующей строке» в VB?
— JBRWilkinson,

1
Только если после символа подчеркивания стоит пробел.
— Роб Виндзор

Начальная буква в нижнем или верхнем регистре отлично
— подходит

0

Нет никаких последствий. Когда ваш код компилируется, все, что важно для компилятора, - это пространство имен поля / свойства и видимость. При именовании идентификатора подчеркивание так же важно, как и любой другой символ. Настоящая уловка состоит в том, чтобы использовать соглашение, которое поймете вы и окружающие вас люди.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.