Главная > Development > Правила оформления кода C# v1.0

Правила оформления кода C# v1.0

Сейчас я занимаюсь проектом, который разрабатывался достаточно большое время, но в разработке не применялось никаких правил оформления кода. Поскольку так жить нельзя, считаю важным привести свое видение того, как имеет смысл оформлять код на C#.

Использование такого стиля позволяет:

  1. Быстро ориентироваться
  2. Не задумываться над оформлением
  3. Применять автоматические инструменты контроля стиля (ReSharper)

Описание рассчитано на использование C# версии 3.5.

Переменные

Использовать значимые имена переменных написанных на правильном английском. Транслитерация названий переменных не допускается.
Хорошо:

private int letters;
private int result;

Плохо:

private int rezultat;
private int oshibka;

Применение венгерской нотации не применяется ни в каких участках кода, ни в GUI, ни в DataAccess, ни в доменной части.
Хорошо:

private int letters;
private string result;

Плохо:

private int iRezultat;
private ComboBox cbItems;

В именах переменных не допускается применение знака подчеркивания. Каждое новое слово пишется с прописной буквы.
Хорошо:

private int lettersToUpdate;
private string lastName;

Плохо:

private int rows_in_table;
private string last_Name;

Переменные не могут начинаться со знака подчеркивания.
Хорошо:

private int lettersToUpdate;
private string lastName;

Плохо:

private int _rows;
private string _lastName;

Только переменные видные извне класса начинаются с прописной буквы. Все остальные типы внутренних переменных начинаются со строчных букв.

Хорошо:

public static int Letters;
public int Letters;
protected int Letters;
internal int Letters;

Плохо:

public static int letters;
public static int LETTERS;
public static int LeTTeRs;

Переменные должны быть понятными, использование однобуквенных переменных допускается только в циклах и порой в лямбда-функциях.

Хорошо:

public static int Letters;
for (var i = 0; i < names.Count; i++) {
...
}
names.Where(s => s.Length > 3).Select(s => s);

Плохо:

private int n;
private List<string> l;

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

Использование var

Использование var в коде допускается. Наличие syntax sugar в виде var помогает меньше печатать, но иногда заставляет задуматься о типе переменной, что снижает скорость работы.

Именование методов

Все методы начинаются с прописной буквы и не содержат в своем названии знака подчеркивания.
Хорошо:

private int GetErrorMessages() {
   …
}

Плохо:

private int get_Error_Messages() {
   …
}

private void save_OnClick(…) {
   …
}

Имена методов должны быть написаны на английском языке. Транслитерация не допускается.
Хорошо:

private int GetStockRates () {
   …
}

Плохо:

private int GetKotirovki () {
   …
}

Первым словом в названии метода должен быть глагол.
Хорошо:

private int LoadStocks() {
   …
}

Плохо:

private int StocksLoad() {
   …
}

Можно использовать универсальные глаголы типа Do или Perform.

Именование методов при возвращении булевого значения не должно формулироваться отрицательно.
Хорошо:

private bool IsValidUser () {
   …
}

Плохо:

private bool IsUserDoNotHaveErrors () {
   …
}

Данные правила направлены на согласованность методов с самим фреймворком, и легкость чтения и понимания.

Обрамление кода

В коде не должно быть регионов (regions), разделения кусков кода комментариями в виде строки и прочее. Все это указывает только на то, что вы написали плохой код, который без вспомогательных средств невозможно прочитать и понять.

Плохо:

#region public fields

public static int Letters;

#endregion

//======== public fields =========================================

public static int Letters;

//======== end public fields =========================================

Комментарии

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

Плохо:

//        public Foo() {
//            Letters = 2;
//        }

Не стоит комментировать каждую строку и писать очевидные вещи.

Плохо:

/// <summary>
/// Отображение данных
/// </summary>
public interface IDataViewer
{
    /// <summary>
    /// Всегда один
    /// </summary>
    bool IsSingle { get; }

    /// <summary>
    /// Сервер
    /// </summary>
    string HostName { get; set; }

    /// <summary>
    /// База данных
    /// </summary>
    string Database { get; set; }

    /// <summary>
    /// Загрузка данных
    /// </summary>
    /// <returns>Результат загрузки</returns>
    bool LoadData();
}

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

Оформление блоков кода

Фигурная открывающая скобка всегда стоит на следующей от конструкции языка строке.
Хорошо:

namespace N
{
    internal interface I
    {
        void foo();
    }

    internal class C
    {}
}

Плохо:

namespace N {
    internal interface I {
        void foo();
    }

    internal class C {}
}

Такой подход позволяет записывать код более компактно и боле четко разграничивать методы визуально.

Свойства

Автосвойства должны быть записаны в одну строку.

Хорошо:

public int Age { get; set; }
public string Login { get; set; }

Плохо:

public int Age {
    get;
    set;
}
public string Login {
    get;
    set;
}

В остальном правила такие же, как и для полей класса.

Логические операции

Длина строки с логическими операциями не должна превышать 80-120 символов. Перенос операций производится с логическим знаком.

Хорошо:

if(boolValue && number >= 0) {
   ...
}

if(string.IsNullOrWhiteSpace(bigCompositeCaption)
   && bigCompositeCaption.StartsWith("x00")
   && bigCompositeCaption.Length > somePositiveNumber) {
     ...
}

Плохо:

if(string.IsNullOrWhiteSpace(bigCompositeCaption) &&
   bigCompositeCaption.StartsWith("x00") &&
   bigCompositeCaption.Length > somePositiveNumber) {
     ...
}

if(string.IsNullOrWhiteSpace(bigCompositeCaption) && bigCompositeCaption.StartsWith("x00") && bigCompositeCaption.Length > somePositiveNumber) {
    ...
}

Форматирование тернарной операции должно быть на несколько строк.

Хорошо:

return boolValue
    ? somePositiveNumber
    : anotherNegativeNumber;

Плохо:

return boolValue ? somePositiveNumber : anotherNegativeNumber;

Исключение может быть сделано только для результатов в 1-3 символа.

Хорошо:

return boolValue ? 1 : -1;

return boolValue ? “Y” : “N”;

Унарная операция ?? так же должна быть с переносом на новую строку, если для записи выражения требуется более ~60 символов.

Хорошо:

return someVeryLongNamedNullable() ?? “N/A”;

return someVeryLongNamedNullable()
    ?? new SomeVeryLongNamedClass();

Плохо:

return someVeryLongNamedNullable() ?? new SomeVeryLongNamedClass();

Строка начинающаяся со знака логической операции показывает, что это все еще идет условие, а не первый оператор при выполнении условия. Сравните:

if(string.IsNullOrWhiteSpace(bigCompositeCaption) &&
   bigCompositeCaption.StartsWith("x00") &&
   bigCompositeCaption.Length > somePositiveNumber)
   bigCompositeCaption.Trim();

if(string.IsNullOrWhiteSpace(bigCompositeCaption)
   && bigCompositeCaption.StartsWith("x00")
   && bigCompositeCaption.Length > somePositiveNumber)
   bigCompositeCaption.Trim();

Специально подобран такой пример, когда в условии используется та же переменная. При договоренности, что перенос условия начинается с логических знаков, легче найти начало блока.

Хочется поблагодарить коллегу violet-tape за его аналогичное состав правил. Множество правил было взято именно у него.

Categories: Development Tags:
  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.