Unity 6.3
0 онлайн 55 гостей 3 в системе
Вход
Руководство по стилю C# для чистого и масштабируемого кода Глава 5 из 13 Оригинал, стр. 23

Форматирование

Форматирование

Если хотите, чтобы код было легко писать, сделайте его удобным для чтения. — Роберт К. Мартин, автор книг «Чистый код» и «Гибкая разработка программного обеспечения»

Чем меньше вы думаете о форматировании, тем больше времени остается на другие задачи.

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

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

Свойства Свойство — это гибкий механизм чтения, записи и вычисления значений класса. Свойства выглядят и используются как открытые поля, но фактически представляют собой специальные методы доступа. Свойство может иметь методы доступа get и set, работающие с закрытым полем — резервным полем (backing field).

Так свойство инкапсулирует данные и защищает их от нежелательных изменений пользователем или внешними объектами. У методов get и set могут быть разные модификаторы доступа, поэтому свойство может поддерживать чтение и запись, только чтение либо только запись. Методы доступа также позволяют проверять или преобразовывать данные: например, контролировать формат значения или переводить его в нужные единицы. Синтаксис свойств может различаться, поэтому руководство по стилю должно определять правила их оформления. Следующие рекомендации помогут сохранить единообразие:

— Для однострочных свойств только для чтения используйте тело выражения (=>): оно возвращает закрытое резервное поле.

C#
// ПРИМЕР: свойства с телом выражения

public class PlayerHealth {
    // резервное поле

    private int m_maxHealth;
    // только чтение: возвращает резервное поле

    public int MaxHealth => m_maxHealth;
    // эквивалентно: //

    public int MaxHealth { get; private set; }
}
— Во всех остальных случаях используйте обычный синтаксис { get; set; }

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

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

C#
// ПРИМЕР: свойства с телом выражения

public class PlayerHealth {
    // резервное поле

    private int m_maxHealth;
    // явная реализация методов get и set

    public int MaxHealth {
        get => m_maxHealth;
        set => m_maxHealth = value;
    }
    // только запись (без резервного поля)

    public int Health { private get; set; }
    // только запись, без явного set

    public SetMaxHealth(int newMaxValue) => _maxHealth = newMaxValue;
}

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

C#
// ПРИМЕР: свойства с телом выражения

public class PlayerHealth {
    // резервное поле

    private int m_maxHealth;
    public int GetMaxHealth { return m_maxHealth; }
}

Сериализация Сериализация скриптов — это автоматическое преобразование структур данных или состояния объектов в формат, который Unity может сохранить и позднее восстановить. Из соображений производительности Unity выполняет сериализацию иначе, чем другие среды программирования. Сериализованные поля отображаются в Inspector, однако статические, константные и доступные только для чтения поля сериализовать нельзя. Поле должно быть открытым либо помеченным атрибутом [SerializeField]. Unity поддерживает сериализацию лишь определенных типов полей; полный набор правил приведен в документации.

При работе с сериализованными полями соблюдайте несколько основных рекомендаций:

— Используйте атрибут [SerializeField]. Он позволяет отображать закрытые и защищенные переменные в Inspector. Это лучше инкапсулирует данные, чем объявление переменной открытой, и не дает внешнему объекту перезаписывать ее значения.

— Задавайте минимальное и максимальное значения атрибутом Range. Атрибут [Range(min, max)] ограничивает допустимое значение числового поля и удобно отображает его в Inspector в виде ползунка. — Группируйте данные в сериализуемые классы или структуры, чтобы упорядочить Inspector. Объявите открытый класс или структуру, пометьте атрибутом [Serializable] и создайте открытые переменные всех типов, которые должны отображаться в Inspector.

C#
// ПРИМЕР: сериализуемый класс PlayerStats

using System;
using UnityEngine;
public class Player : MonoBehaviour {
    [Serializable] public struct PlayerStats {
        public int MovementSpeed;
        public int HitPoints;
        public bool HasHealthPotion;
    }
    // ПРИМЕР: закрытое поле отображается в Inspector

    [SerializeField] private PlayerStats m_stats;
}

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

Сериализуемый класс или структура помогают упорядочить Inspector.

Стиль скобок и отступов В C# распространены два стиля отступов: — В стиле Олмана открывающая фигурная скобка размещается с новой строки. Этот стиль также называют BSD-стилем, по имени BSD Unix. — В стиле K&R, также известном как «единственно верный стиль скобок», открывающая скобка остается в той же строке, что и предшествующая конструкция.

C#
// ПРИМЕР: в стиле Олмана, или BSD, открывающая скобка находится на новой строке.
C#
void DisplayMouseCursor(bool showMouse) {
    if (!showMouse) {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
    else {

Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } }

C#
// ПРИМЕР: в стиле K&R открывающая скобка остается в строке заголовка.

void DisplayMouseCursor(bool showMouse) {
    if (!showMouse) {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
    else {
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
    }
}

Существуют и другие варианты этих стилей. В примерах руководства применяется стиль Олмана из Microsoft Framework Design Guidelines. Какой бы вариант ни выбрала команда, все должны придерживаться одинаковых правил отступов и расстановки скобок. Следуйте этим рекомендациям: — Установите единый отступ. Обычно используют два или четыре пробела. Согласуйте настройку редактора со всей командой, не разжигая спор о табуляции и пробелах. Visual Studio умеет преобразовывать знаки табуляции в пробелы.

В Visual Studio (Windows) выберите Tools > Options > Text Editor > C# > Tabs..

Настройки табуляции в Visual Studio

В Visual Studio for Mac выберите Visual Studio > Preferences > Source Code > C# Source Code, а затем настройте параметры на вкладке Text Style.

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

— По возможности не опускайте фигурные скобки даже в однострочных конструкциях. Это повышает единообразие и упрощает чтение и сопровождение кода. В примере скобки четко отделяют вызов DoSomething от цикла. Если позднее понадобится добавить строку отладочного вывода или вызвать DoSomethingElse, скобки уже будут на месте. Некоторые программисты также считают, что отдельная строка для выражения позволяет проще поставить точку останова.

C#
// ПРИМЕР: сохраняйте скобки для ясности... for (int i = 0;

i < 100;
i++) { DoSomething(i); }
// …и/или вынесите выражение в отдельную строку. for (int i = 0;

i < 100;
i++) { DoSomething(i); }
// ИЗБЕГАЙТЕ: опускать скобки for (int i = 0;

i < 100;
i++) DoSomething(i);
— Не удаляйте скобки из вложенных многострочных конструкций. Ошибки компиляции не возникнет, но код станет запутаннее. Используйте скобки для ясности, даже когда они необязательны. Кроме того, с ними можно безопасно добавлять новую логику, не перестраивая окружающий код.
C#
// ПРИМЕР: сохраняйте скобки для ясности for (int i = 0;

i < 10;
i++) {
    for (int j = 0;
    j < 10;
    j++) { ExampleAction(); }
}
// ИЗБЕГАЙТЕ: удалять скобки из вложенных многострочных конструкций for (int i = 0;

i < 10;
i++) for (int j = 0;
j < 10;
j++) ExampleAction();

— Унифицируйте оформление операторов switch. Для удобства чтения длинные цепочки if-else обычно лучше заменять оператором switch. В этом примере метки case оформлены с отступом. Как правило, стоит добавлять и ветвь default. Даже если все варианты уже охвачены, ветвь default позволит обработать неожиданное значение.

C#
// ПРИМЕР: метки case имеют отступ относительно switch switch (someExpression) {

    case 0: DoSomething();
    break;
    case 1: DoSomethingElse();
    break;
    case 2: int n = 1;
    DoAnotherThing(n);
    break;
    default: // Обработка неожиданного значения или ветви default break;

}

Что такое EditorConfig? Если над одним проектом работают несколько разработчиков, использующих разные редакторы и IDE, стоит задействовать файл EditorConfig. EditorConfig помогает определить единый стиль кода для всей команды. Многие IDE, включая Visual Studio и Rider, поддерживают его изначально и не требуют отдельного плагина. Файлы EditorConfig легко читать и удобно хранить в системе контроля версий. Пример такого файла приведен здесь. Настройки стиля из EditorConfig хранятся вместе с кодом и могут применяться даже вне Visual Studio. Параметры EditorConfig имеют приоритет над глобальными настройками текстового редактора Visual Studio. Личные настройки редактора продолжают действовать в проектах без файла .editorconfig и для параметров, которые этот файл не переопределяет.

Практические примеры можно найти в репозитории GitHub.

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

— Добавляйте пробелы, чтобы снизить плотность кода. Дополнительное пустое пространство визуально разделяет части строки и облегчает чтение.

C#
// ПРИМЕР: пробелы делают строку удобнее для чтения for (int i = 0;

i < 100;
i++) { DoSomething(i); }
// НЕВЕРНО: без пробелов for(inti=0;

i<100;
i++){DoSomething(i);}
— Ставьте один пробел после запятой между аргументами метода. . // ПРИМЕР: один пробел после запятой между аргументами CollectItem(myObject, 0, 1);
// ИЗБЕГАЙТЕ: пропускать пробел CollectItem(myObject,0,1);

— Не ставьте пробелы внутри круглых скобок: ни после открывающей, ни. перед закрывающей.
C#
// ПРИМЕР: без пробелов внутри круглых скобок DropPowerUp(myPrefab, 0, 1);
// ИЗБЕГАЙТЕ: DropPowerUp( myPrefab, 0, 1 );

— Не ставьте пробел между именем метода и открывающей скобкой. . // ПРИМЕР: без пробела между именем метода и открывающей скобкой. DoSomething() // ИЗБЕГАЙТЕ DoSomething () — Не добавляйте пробелы внутри. квадратных скобок. // ПРИМЕР: без пробелов внутри квадратных скобок x = dataArray[index];
// ИЗБЕГАЙТЕ x = dataArray[ index ];

— Ставьте один пробел перед условием управляющей конструкции: отделяйте условие в круглых скобках от ключевого слова. // ПРИМЕР: пробел перед условием; круглые скобки отделены пробелом. while (x == y) // ИЗБЕГАЙТЕ while(x==y) — Ставьте по одному пробелу до и после операторов сравнения. . // ПРИМЕР: пробелы до и после оператора сравнения. if (x == y) // ИЗБЕГАЙТЕ if (x==y) — Делайте строки короткими и учитывайте горизонтальные пробелы. Установите стандартную ширину строки в 80–120 символов. Длинную строку лучше разбить на несколько выражений, чем допустить ее переполнение.

— Соблюдайте отступы и иерархию. Отступы повышают читаемость кода. — Не выравнивайте код по столбцам без необходимости. Такое размещение выравнивает переменные, но мешает сопоставлять тип с именем. При этом выравнивание по столбцам может быть полезно для побитовых выражений или структур с большим объемом данных. Помните, что при добавлении элементов его придется поддерживать вручную, а некоторые автоформаттеры могут изменить выравниваемую часть столбца.

C#
// ПРИМЕР: один пробел между типом и именем

public float Speed = 12f;
public float Gravity = -10f;
public float JumpHeight = 2f;
public Transform GroundCheck;
public float GroundDistance = 0.4f;
public LayerMask GroundMask;
// ИЗБЕГАЙТЕ: выравнивания по столбцам

public float

Speed = 12f;

public float

Gravity = -10f;

public float

JumpHeight = 2f;

public Transform

GroundCheck;

public float

GroundDistance = 0.4f;

public LayerMask

GroundMask;

Вертикальные отступы Вертикальные отступы тоже помогают организовать код. Располагайте связанные части скрипта рядом и осмысленно используйте пустые строки. Следующие рекомендации упорядочат код сверху вниз:

— Группируйте зависимые и похожие методы. Код должен быть логичным и связным. Размещайте рядом методы, выполняющие сходные задачи, чтобы читателю не приходилось перемещаться по всему файлу. — Отделяйте разные части класса пустыми строками. Например, можно оставить две пустые строки между: — объявлениями переменных и методами — классами и интерфейсами — блоками if-then-else, если это улучшает читаемость Не злоупотребляйте этим приемом и зафиксируйте в руководстве по стилю, где он уместен.

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

Примечание. Многие разработчики считают области признаком проблемного кода или антипаттерном. Команде следует договориться о едином подходе.

Форматирование кода в Visual Studio Не пугайтесь, если правил форматирования кажется слишком много. Современные IDE позволяют быстро настраивать и применять их. Можно создать шаблон правил форматирования и сразу применить его ко всем файлам проекта. Чтобы настроить правила форматирования в редакторе скриптов: — В Visual Studio (Windows) выберите Tools > Options, затем Text Editor > C# > Code Style > Formatting. Настройте параметры General, Indentation, New Lines, Spacing и Wrapping.

Параметры форматирования кода

— В Visual Studio for Mac выберите Visual Studio > Preferences, затем Source Code > Code Formatting > C# Source Code. В верхней части окна выберите Policy. Настройте пробелы и отступы на вкладке Text Style, а параметры Indentation, New Lines, Spacing и Wrapping — на вкладке C# Format.

В окне Preview отображается результат выбранных настроек стиля.

Чтобы в любой момент привести файл скрипта в соответствие с руководством по стилю:

— В Visual Studio (Windows) выберите Edit > Advanced > Format Document (Ctrl+K, Ctrl+D). Если нужно отформатировать только пробелы и выровнять табуляцию, в нижней части редактора можно запустить Run Code Cleanup (Ctrl+K, Ctrl+E). — В Visual Studio for Mac выберите Edit > Format Document (Ctrl+I). В Windows настройки редактора можно передать через Tools > Import and Export Settings. Экспортируйте файл с правилами форматирования C# из руководства по стилю и попросите каждого участника команды импортировать его.

Экспорт настроек форматирования C# для совместного использования.

Visual Studio упрощает соблюдение руководства по стилю: для форматирования достаточно сочетания клавиш.

Примечание. Вместо импорта и экспорта настроек Visual Studio можно настроить файл EditorConfig, описанный выше. Так правила форматирования проще использовать в разных IDE и хранить в системе контроля версий. Дополнительные сведения см. в параметрах правил стиля кода .NET.

Хотя это не относится напрямую к чистому коду, рекомендуем посмотреть доклад GDC «Советы и приемы Visual Studio для повышения продуктивности». Эти советы упрощают форматирование и рефакторинг чистого кода.

Чтобы настроить файл .editorconfig в Visual Studio Code: 1. Создайте в корневом каталоге проекта файл с именем .editorconfig. 2. Откройте файл .editorconfig и добавьте нужные параметры. Ниже приведен пример конфигурации для C#:

# корневой файл EditorConfig root = true # переводы строк в стиле Unix; каждый файл заканчивается новой строкой

[*] end_of_line = lf insert_final_newline = true # отступ в 4 пробела [*.cs] indent_style = space indent_size = 4 charset = utf-8 trim_trailing_whitespace = true # отступы табуляцией для Makefile [Makefile] indent_style = tab # отдельные параметры для файлов JSON [*.json] indent_style = space indent_size = 2