Комментарии 117
По поводу
3.1 Закрытые поля - я за третий вариант. Первый - это С++, а со вторым вообще не встречался никогда.
3.2 насчет скобок с новой строки поддерживаю, касательно if руководствуюсь такими принципами:
- если в выражении одна строка, то пишу без скобок
- если в if одна строка, а в else несколько (или наоборот), то обе конструкции пишу с фигурными скобками, для более легкой читаемости.
- не использую конструкцию вида if(condition) doSomesthing(); Т.е. не использую однострочную конструкцию if.
Второй вариант закрытых полей описан в предложении первого источника, приведенного в начале.
Про if: я поступаю точно так же как и ты, но очевидно, что назвать стандартом проще действие через одно условие, чем через три. Вариант который приведен в статье описан во втором источнике. Причин там не описывается, но я думаю, все дело в читаемости и принципе: область видимости всегда в фигурных скобках. В целом с тобой согласен, но, наверное, стоит еще чье-нибудь мнение послушать, чтобы внести изменения.
в нотации 1 это:
private int m_myVar;
private static int s_myVar;
private const int s_myVar = 10;
А еще при необходимости можно добавлять префикс идентифицирующий тип переменной m_iMyVar для Int32 или m_lMyVar для Int64 (long)
Если это закрытое поле (а оно в 99% случаев закрыто), то
private int _myVar;
Константы никак не рекомендуется выделять от других полей, чего и я не делаю.
Статические поля.. К статическому полю нельзя обратиться без имени класса в нестатическом методе. А в статическом - к обычным полям класса. Тут наглядно будет разделение, как по мне и так.
Тип данных в виде префикса - тоже никогда не использую и нет рекомендаций по этому поводу, касательно C#.
txtSample - TextBox
lblSample - Label
litSample - Literal
cmdSample - Button, LinkButton, ImageButton
lstSample - Все списковые элементы
odsSample - ObjectDataSource
lnkSample - Hyperlink
imgSample - Image
ну и оcтальные по такому же принципу.
Если этим пользуются остальные, то можно тоже включить в соглашение. Таким же принципом пользуюсь для именования контролов в WinForms
SampleTextbox,
SampleLabel,
SampleLiteral,
SampleList,
SampleObjectDataSource,
SampleHyperlink,
SampleImage
на самом деле, проигрыш в длине переменной небольшой, но наглядности больше. Как думаешь?
И для меня нагляднее, когда название строится по схеме [тип контрола][за что отвечает].
Хотя так действительно нагляднее и психологически удобнееimho ;)
Было бы неплохо, если в IDE была бы автоматическая подстановка по любой подстроке, не только по началу. Т.е. ты вводишь несколько букв, а оно тебе сразу список того, где эти буквы встречаются.
Я перешел из именования, типа SampleLabel, в основном по этой причине.
Вообщем, когда придётся какую отдельную программу начинать писать — попробую ;) Спасибо ;)
А каким способом сейчас названия даешь?
А метки (Label) вообще никак не именую, если они никогда не изменяются. Даже не знаю, плохо ли это или сойдёт ;) До сих пор проблем не было ;)
SampleLabel. Потом как-то перешел на более удобный для себя.
btnSample - Button, LinkButton, ImageButton
ddlSample - Все списковые элементы
Хотя Ваш вариант тоже неплох.
lbl Label
llbl LinkLabel
but Button
txt Textbox
mnu MainMenu
chk CheckBox
rdo RadioButton
grp GroupBox
pic PictureBox
grd Grid
lst ListBox
cbo ComboBox
lstv ListView
tre TreeView
tab TabControl
dtm DateTimePicker
mon MonthCalendar
sbr ScrollBar
tmr Timer
spl Splitter
dud DomainUpDown
nud NumericUpDown
trk TrackBar
pro ProgressBar
rtxt RichTextBox
img ImageList
hlp HelpProvider
tip ToolTip
cmnu ContextMenu
tbr ToolBar
frm Form
bar StatusBar
nico NotifyIcon
ofd OpenFileDialog
sfd SaveFileDialog
fd FontDialog
cd ColorDialog
pd PrintDialog
ppd PrintPreviewDialog
ppc PrintPreviewControl
err ErrorProvider
pdoc PrintDocument
psd PageSetupDialog
crv CrystalReportViewer
pd PrintDialog
fsw FileSystemWatcher
log EventLog
dire DirectoryEntry
dirs DirectorySearcher
msq MessageQueue
pco PerformanceCounter
pro Process
ser ServiceController
rpt ReportDocument
ds DataSet
olea OleDbDataAdapter
olec OleDbConnection
oled OleDbCommand
sqla SqlDbDataAdapter
sqlc SqlDbConnection
sqld SqlDbCommand
dvw DataView
Мои комментарии и дополнения :)
1. Приватные поля - начинать имена с подчеркивания и маленькой буквы.
2. Скобки - я за то, чтобы ставить их всегда. А то иногда одну строчку после условия особо умные комментируют и начинается магия :) - if распространяется на следующую.
3. Про именование контролов - всеми руками за вариант dmx. Точно такой же практикой пользуемся.
А насчет наглядности - после двух-трех дней пользования сокращениями, поймете, что все-таки, они лучше. Нежели сто раз в день видеть TextBox, Literal, ObjectDataSource.
4. Про оформление классов - сначала пишутся все приватные и защищенные поля, позже идут свойства, далее - методы - сначала приватные, потом защищенные и наконец общие.
Обычно, если более одного метода, свойства, поля - мы объединяем в регионы.
Пока ничего больше в голову не приходит...
2. Я тоже за то, чтобы всегда ставить скобки.
3. Я тоже пользуюсь, но когда начинаешь встречать в чужом коде btnSample вместо cmdSample и многое другое не настолько очевидное, начинаешь задумываться, а так ли это уж и правильно? Такая нотация интересная когда она навязана свержу, типа венгерской, которую знали все, потому-что win32 api написан на ней. Но свой вариант нотации - это уже палка о двух концах: себе удобнее, другим все равно...
Button - btn.
ImageButton - тоже btn(потому как наследник Button).
Думаю можно просто включить как рекомендацию.
И префикс трехбуквенный я всегда даю.
Сейчас посмотрю что вообще насчет этого гугл говорит.
Не обязательно в контексте .net, это вроде внеязыковый момент.
Пришел к выводу, что пусть это останется личным делом каждого. Куча статей, и куча разных мнений. Кстати, ко всем вышеобговоренным ещё одно нашел:
Именовать все контролы с префикса ux (User eXperience). Это позволяет в IntelliSense группировать все, что относится к интерфейсу. Говорят удобно :)
PS. cmd, да, от Command. Тут больше происходит от действия, чем от названия самого элемента.
Порядок декларации преследует те же цели. Я, кстати, использую немного другой:
1). private static поля. Константы.
2). private, protected, protected internal поля (и вообще поля, просто public я использую крайне редко)
3). Конструкторы (от общих к более частным), если есть статический - то ставится в начале списка.
4). Статические свойства, в порядке расширения области доступности
5). Instance-свойства, в порядке расширения области доступности
6). Статические методы, в порядке расширения области доступности
7). Instance-методы, в порядке расширения области доступности
8). Явные реализации интерфейсов (explicit interface implementations), если таковые применяются
Для использования в публикациях это, наверно, не важно, а для собственно программирования стоит включить, это действительно упрощает жизнь.
И любая объявленная переменная или поле должны иметь значение
private List _names = null;
int x = 0;
Понятно, что все знают (или почти все), какое там будет значение по умолчанию, однако, с таким дополнением легче читать код.
Не вижу смысла только в этом: - утвердить как стандарт написания C# кода на Хабре =)
Примеры, как известно, для того, чтобы учиться, а учиться, как известно, лучше хорошему.
Еще я могу дать бесплатную лицензию на CodeIt.Right - наш тул который проверяет и автоматически исправляет код под стандарты - в обмен на ваши отзывы и мнения.
- ваш документ описывает кроме всего прочего рекомендации и по vb.
- ваш документ более глубокий, по сравнению с вариантом IDesign и больше походит на стандарт, в то время как вариант IDesign - это в большей степени guidline;
- ваш документ лучше в том смысле, что в темах именования предлагает не только то "что надо делать", но и описывает "то что делать не нужно". Справедливости ради надо заметить, что вариант IDesign так же в большом числе описывает то, чего делать не следует, но это все касается больше уже не именования, а стиля программирования в целом;
- у вас гораздо больше примеров, в то время как вариант IDesign более лаконичный;
- у вас есть таблица стандартного именования префиксов для пользовательских элементов, то о чем сейчас идет дискуссия в этом топике;
- субъективно: в целом, ваш документ более глубок, тогда как IDesign более дружелюбен, если так можно выразиться.
Рекомендовал бы включить также следующие рекомендации:
1. Используйте пустую строку между логическими секциями в исходном файле, классе, методе
2. Для временных локальных переменных, используемых в коротких участках кода, можно давать имена, состоящие из начальных букв слов имени типа.
... и не применять 2.2 для переменных цикла :)
Ну и со вторым - LoanTableAdapter lta = new LoanTableAdapter();
2. спорно. Нет, конечно, это удобно, но правильно ли?
3. слава богу 2.2 - это только рекомендация :)
Ага, сам так часто поступаю, в том числе и для команд, например:
SqlCommand command = new SqlCommand();
Но чаще эта методика применяется при именовании формальных параметров метода. На самом деле, тяжело разобраться, как оно там правильно. Замечал, что вариант с префиксами используется в основном для контролов, сокращения от имени типа в локальных переменных. Но спорить не буду :)
Пункт 3.2 насчёт скобок для if можно расширить. Предлагаю разрешить использовать if, for и другие конструкции без скобок (кстати, вы знали, что using тоже можно использовать без скобок?) в случае, если каждая ветвь данного выражения полностью умещается в одну строку:
if (addressAttr != null) address = addessAttr.Value;
Если же хотя бы одна ветвь (в данном случае у if) не умещается в одну строку — в фигурные скобки оформляются все ветви, даже else:
if (portAttr != null) { int port; if (int.TryParse(portAttr.Value, out port)) Settings.Port = port; else throw new Exception("..."); } else { Settings.Port = DefaultSettings.Port; }
Мое личное мнение.
Это относится не только к ранним библиотекам, но и к последним продуктам, вроде Linq, ASP.NET MVC, EF... Воистину, привычка свыше нам дана...
Я интересовался этим в декабре 2007 применительно к оформлению кода на C#, на тот момент мне удалось найти следующие ресурсы (по крайней мере продукты SubMain я тогда не нашел):
Документ от Phillips о конвенциях оформления С# [PDF]
ClockSharp Code Checker
Оба ресурса ведут на сайт организации TIOBE, которая славится своими рейтингами языков программирования.
Как то мне кажется читаемость не улучшается от этого (имхо даже ухудшается), а время на создание переменной уходит, и если это будет в большущем цикле, то, думаю, негативно отразится на времени выполнения.
Пять - это уже далеко за пределами разумного.
Я для себя использую почти полностью аналогичные правила. Расхождения у меня, например, вот только в именовании закрытых и защищенных полей. Я и те, и другие с префиксовым "_" именую. Ну и скобки фигурные для однострочного ифа редко пользую.
Несколько моментов для рассмотрения:
- в суффиксы добавить EventHandler - для пользовательских обработчиков
- выбор коротких имен примитивных типов вместо полных(int, bool вместо Int32, Boolean). Отмечу, что для себя использую всегда короткие имена типов, кроме случаев для целочисленных типов, когда в контексте важен размер переменной.
И еще вдогонку :) Уже неотносительно топика, так как это вопрос не сильно важный, но мне интересно чужое мнение. Я не так давно думал на тему, когда стоит вместо get-свойства использовать метод Get...() без параметров. Надумал, что единственным случаем, когда следует использовать второй вариант, - чтобы указать что связанное с методом действие является "процессом", то есть может вызвать существенные временные задержки.
CLR-типы вообще не рекомендуется использовать при программировании и тут вопрос уже не оформления кода, имхо.
Из ваших ссылок удалось найти только рекомендации НАЗЫВАТЬ имена методов используя CLR-имена.
For example, a method that converts data to Int16 should be named ToInt16, not ToShort because Short is the language-specific type name for Int16. (c)msdn
Кратко используйте свойства, если все нижесказанное верно:
get-аксессоры не содержат сложной логики и не должны вызывать исключения. В них не следует обращаться к базам данных или сетевым ресурсам, так как неудачные попытки могут вызвать исключение.
Одно свойство не должно зависеть от других. Также, изменение одного свойства не должно влиять на остальные.
Порядок присвоения (set) может быть любым.
Вызов get-аксессора не должен иметь заметных побочных эффектов (это не запрещает «ленивых вычислений»).
get-аксессор должен немедленно возвращать управление. Это исключает возможность использования get-аксессора для обращений к базе данных, web-сервисам и т.д.
get-аксессор не возвращает массивы.
повторные вызовы get-аксессора (без изменения прочих условий) возвращают одинаковые значения.
несколько вызовов set-аксессора с одинаковым аргументом ничем не отличаются от одиночного вызова.
get-аксессор не должен возвращать ссылку на некие внутренние структуры данных. Можно избежать этого, возвращая «глубокую копию»
избегайте файлов с более чем 500 строками кода;
нервно чешу репу...
а как быть если обстоятельства вынуждают? partial использовать !? ...не понимаю... :")
> Pascal casing для констант.
Я для себя решаю так: если константа публична, имя начинается с большой буквы. Если нет, то с маленькой. Если вдруг она перестанет быть константой и превратится в переменную, программу не придётся переписывать (хотя при наличии Refactoring rename это уже не так актуально, как раньше).
> При именовании переменных избегайте использования сокращенных вариантов вроде I и t,
> используйте index и temp. Не используйте венгерскую нотацию или используйте ее только для
> закрытых членов. Не сокращайте слова, используйте number, а не num.
Спорно. По крайей мере, существуют устоявшиеся конструкции, которые одинакого воспринимаются всеми без исключения программистами. Одна из них for(int i = 0; i < limit; i++).
Схватывается целиком. Ну и в целом, есть определённое количество случаев, когда короткие имена понимаются на лету. Постараюсь перечислить:
1. Математические функции. Например sin(T x) или atan2(T y, T x).
2. Целые переменные во вложенных циклах for: i, j, k...
3. Функции с говорящими именами, параметры которых не несут самостоятельного смысла: swap(T a, T b)
Кроме того, в коротких методах с простой структурой, я предпочитаю называть локальные переменные по большим буквам их типа. Например, FileInfo fi, DataReader dr. Ну, и отсюда с необходимостью следуют string s, File f, но только в том случае, если назначение этих переменных очевидно из названия метода.
По поводу num и number согласен.
> используйте промежуточную переменную для передачи bool-значения результата функции в
> условное выражение if;
Такой код для меня однозначно "с запашком" (по Фаулеру). Я обязательно при чтении остановлюсь и начнут думать: зачем сделали именно так? Думаю, эту рекомендацию надо убрать.
> избегайте методов с более чем 200 строками кода;
На мой взгляд, 20 является прекрасной верхней границей. :) Если встречаю большую функцию, рука сама тянется к Refactoring, Extract method. Ключ к читабельности программы вижу в том, что любой метод помещается на экране монитора полностью, тогда все остальные огрехи не так страшны.
> 3.1 Закрытые поля
Сам лично избегаю префиксов и в этом случае тоже. Если внешнее свойство называется Length, закрытая переменная будет называться length. Тут, сам понимаю — момент очень спорный. Тем не менее, считаю, что любые префиксы зло.
1. Избегать избыточности в именах. Пример: пишем обёртку над ActiveDirectory, пространство имён называем ActiveDirectory. Классы внутри должны назвать User, Group, Computer, а не ADUser, ADGroup, ADComputer.
Второй пример:
class File
{
enum Mode { Read, Write };
}
File.Mode.Read, а не File.FileMode.Read и уж тем более не File.FileMode.ModeRead.
Третий пример, названия методов: File.Open, но не File.OpenFile.
2. Именование множественных объектов. Если есть объект класса T, то коллекцию называем TCollection, список TList. То есть StringCollection, StringList, но не StringsCollection, StringsList. Точно так же предлагаю стыковать имя класса с суффиксом Count: FieldCount, StringCount, FileCount.
Во множественном числе можно называть имена переменных, например FieldCollections fields.
3. Логические переменные, свойства и пр., имеют прифексы is, has: IsDeleted, но не Deleted, HasMoreElements, но не ContainsMoreElements.
4. Правила переноса длинных строк.
4.1. В случае сложных выражений необходимо выделить логическую структуру выражения, вынести отдельные блоки в самостоятельные операторы присваивания.
double velocity = sqrt(sqr(x1 - x2) + sql(y1 - y2))/time;
Должно быть:
double distance = sqrt(sqr(x1 - x2) + sql(y1 - y2));
double velocity = distance/time;
Методы с большим числом параметров, которые не помещаются на одну строку, оформляются так:
. . .
VeryManyArguments(
arg1,
arg2,
arg3,
arg4, // а здесь можно и комментировать
arg5,
arg6,
arg7
);
. . .
Про избыточность в именах согласен, но опять же думаю стоит этот момент оставить на совести программиста, определив только casing-правила.
С последним (про методы) лично не согласен, а в контексте правил считаю лишним.
int DoSmth() {
try {
...
} catch(...) {
}
}
как по мне очень экономит место и улучшает общую читаемость кода.... Глаза не цепляются за лишние строчки.
Тут дело привычки, и я думаю ни вы не перейдете на предложенный автором метод, ни я на ваш. Мне вот в том примере, который вы привели, уже тяжело сразу взглядом схватить какие там конструкции.
Тут дело, наверное, в том, кто с какого языка перешел на C#.
public Guid workflowId = default(System.Guid);
public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties workflowProperties = new Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties();
Кому поможет это стандарт написания ПРИМЕРОВ? Кто его будет использовать? Что, тех кто опубликовал что-то не по стандарту - штрафовать будем? Код ревью на хабре проводить, да? Метрики собирать?
Бред, абсолютный бред.
Давайте немедленно обсудим, проголосуем и утвердим!
Бегло пролистал комменты и не увидел ссылки на это — https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
Не хочу быть Колумбом, но вот ваша Америка. Все придумали давно и за вас.
Почему вы используете сокращенные префиксы, но против венгерской нотации? Это вызывает во мне противоречия.
Зачем обязывать переносить открывающие скобки на новую строку?
Я против, чтобы меня это заставляли делать в сообществе, потому что это экономит место на моем мониторе, когда я читаю пост, и не мешает читабельности кода, потому что есть отступы, которые показывают, где начинается блок.
Если вы пишите какие-то рекомендации, откажитесь от синдрома утенка и вносите рекомендации только после того, как найдете им обоснование. Если вы рекомендуете что-то просто потому что привыкли — грош цена вашим рекомендациям, это ваше личное, не распространяйте это на других.
Используйте конструкцию глагол-объект для именования методов
имена делегатов обработчиков событий всегда оканчиваются суффиксом EventHandler
Подскажите, а какую конструкцию использовать для обычных делегатов, не связанных с обработкой событий? Для именования методов глагол-объект. А какую конструкцию использовать для делегатов? Просто добавлять слово Delegate?
C#: требования и рекомендации по написанию кода