Настанови по стилю C#

Мати чітко визначені та узгоджені умови кодування, важливо для кожного проекту, і Godot не є винятком із цього правила.

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

Примітка

Ця стаття аж ніяк не є вичерпним посібником щодо того, як слід дотримуватися стандартних угод про кодування чи найкращих практик. Якщо ви не впевнені в аспекті, який тут не висвітлюється, зверніться до більш всеосяжної документації, наприклад, `C# Конвенції про кодування<https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions>`_, або Правила дизайну.

Специфікація мови

Godot, в даний час, використовує C# версії 7.0 у своєму двигуні та прикладі вихідного коду. Отже, перед тим, як перейти до нової версії, слід подбати про те, щоб уникнути змішування функцій мови, доступних лише на C# 7.1, або новіших версіях.

Детальну інформацію про функції C# у різних версіях дивіться у Що нового у C#.

Форматування

Загальні вказівки

  • Використовуйте символи передачі рядків (LF) для переривання рядків, а не CRLF, чи CR.
  • Використовуйте один символ передачі рядка в кінці кожного файлу, за винятком файлів csproj.
  • Використовуйте кодування UTF-8 без byte order mark.
  • Використовуйте 4 пробіли замість вкладок (tabs) для відступу (які називається "м'якими вкладками").
  • Подумайте про розрив рядка на кілька, якщо він довший 100 символів.

Розриви рядків та порожні рядки

Для загального правила відступу дотримуйтесь "стилю Олмана", який рекомендує розмістити дужку, пов'язану з контрольним оператором, на наступному рядку з відступом на той самий рівень:

// Use this style:
if (x > 0)
{
    DoSomething();
}

// NOT this:
if (x > 0) {
    DoSomething();
}

Однак ви можете опустити розриви рядків у дужках:

  • Для простих property accessors (додаткових властивостей(?)).
  • Для простих ініціалізаторів об'єктів, масивів, або колекцій.
  • For abstract auto property, indexer, or event declarations.
// You may put the brackets in a single line in following cases:
public interface MyInterface
{
    int MyProperty { get; set; }
}

public class MyClass : ParentClass
{
    public int Value
    {
        get { return 0; }
        set
        {
            ArrayValue = new [] {value};
        }
    }
}

Вставляйте порожній рядок:

  • Після списку using.
  • Між методом, властивостями та внутрішнім типом оголошень.
  • В кінці кожного файлу.

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

Не вставляйте порожній рядок:

  • Після {, (відкриваюча дужка).
  • Перед }, (закриваюча дужка).
  • Після блоку коментарів, або однорядкового коментаря.
  • Поруч з іншим порожнім рядком.
using System;
using Godot;
                                          // Blank line after `using` list.
public class MyClass
{                                         // No blank line after `{`.
    public enum MyEnum
    {
        Value,
        AnotherValue                      // No blank line before `}`.
    }
                                          // Blank line around inner types.
    public const int SomeConstant = 1;
    public const int AnotherConstant = 2;

    private Vector3 _x;                  // Related constants or fields can be
    private Vector3 _y;                  // grouped together.

    private float _width;
    private float _height;

    public int MyProperty { get; set; }
                                          // Blank line around properties.
    public void MyMethod()
    {
        // Some comment.
        AnotherMethod();                  // No blank line after a comment.
    }
                                          // Blank line around methods.
    public void AnotherMethod()
    {
    }
}

Використання пробілів

Вставляйте пробіл:

  • Навколо бінарних та третинних операторів.
  • Між відкриваючою дужкою і ключовими словами if, for, foreach, catch, while, lock, або using.
  • До і в межах однорядкового блоку доступу.
  • Between accessors in a single line accessor block.
  • Після коми, яка не знаходиться в кінці рядка.
  • Після крапки з комою в виразі for.
  • Після двокрапки в одномурядковому виразі case.
  • Навколо двокрапки в оголошенні типу.
  • Навколо стріли лямбда.
  • Після коментаря однорядкового символу ( //) і перед ним, якщо він використовується в кінці рядка.

Не використовуйте пробіл:

  • Після переведення типу в круглих дужках.
  • Всередині однорядкових дужок ініціалізатора.

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

public class MyClass<A, B> : Parent<A, B>
{
    public float MyProperty { get; set; }

    public float AnotherProperty
    {
        get { return MyProperty; }
    }

    public void MyMethod()
    {
        int[] values = {1, 2, 3, 4}; // No space within initializer brackets.
        int sum = 0;

        // Single line comment.
        for (int i = 0; i < values.Length; i++)
        {
            switch (i)
            {
                case 3: return;
                default:
                    sum += i > 2 ? 0 : 1;
                    break;
            }
        }

        i += (int)MyProperty; // No space after a type cast.
    }
}

Конвенції іменування

Використовуйте PascalCase для всіх просторів імен, імен типів та ідентифікаторів рівня елементів (тобто методів, властивостей, констант, подій), за винятком приватних полів:

namespace ExampleProject
{
    public class PlayerCharacter
    {
        public const float DefaultSpeed = 10f;

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

Використовуйте camelCase для всіх інших ідентифікаторів (тобто локальних змінних, аргументів методу) та використовуйте підкреслення (_), як префікс, для приватних полів (але не для методів, чи властивостей, як пояснено вище):

private Vector3 _aimingAt; // Use a `_` prefix for private fields.

private void Attack(float attackStrength)
{
    Enemy targetFound = FindTarget(_aimingAt);

    targetFound?.Hit(attackStrength);
}

Є виняток із абревіатур, які складаються з двох букв, як-от UI, які слід писати великими літерами, де очікується PascalCase, та малими літерами в іншому випадку.

Зауважте, що id не є абревіатурою, тому його слід трактувати як звичайний ідентифікатор:

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

Зазвичай не рекомендується використовувати ім'я типу, як префікс ідентифікатора, наприклад``string strText``, або float fPower. Виняток робиться для інтерфейсів, які повинні, по суті, мати велику букву I, як приставку до їх імен, як от IInventoryHolder або IDamageable.

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

Наприклад, якщо ви хочете написати код, щоб знайти ворога, який знаходиться поблизу, і вдарити його зброєю, віддайте перевагу:

FindNearbyEnemy()?.Damage(weaponDamage);

Замість:

FindNode()?.Change(wpnDmg);

Member variables

Don't declare member variables if they are only used locally in a method, as it makes the code more difficult to follow. Instead, declare them as local variables in the method's body.

Local variables

Declare local variables as close as possible to their first use. This makes it easier to follow the code, without having to scroll too much to find where the variable was declared.

Локальні змінні із неявною типізацією

Розгляньте можливість неявної типізації (var) для декларування локальної змінної, але робіть це лише тоді, коли тип видно з правого боку призначення:

// You can use `var` for these cases:

var direction = new Vector2(1, 0);

var value = (int)speed;

var text = "Some value";

for (var i = 0; i < 10; i++)
{
}

// But not for these:

var value = GetValue();

var velocity = direction * 1.5;

// It's generally a better idea to use explicit typing for numeric values, especially with
// the existence of the `real_t` alias in Godot, which can either be double or float
// depending on the build configuration.

var value = 1.5;

Інші загальноприйняті правила

  • Використовуйте явні модифікатори доступу.
  • Use properties instead of non-private fields.
  • Використовуйте модифікатори в такому порядку: public/protected/private/internal/virtual/override/ abstract/new/static/readonly.
  • Уникайте використання повно-кваліфікованих імен, або префіксу this., для членів, коли це не потрібно.
  • Видаліть невикористані using оператори та непотрібні дужки.
  • Спробуйте не вказати початкове значення за замовчуванням для типу.
  • Щоб зробити код більш компактним, розгляньте можливість використання нульових умовних операторів, або ініціалізаторів типів.
  • Use safe cast when there is a possibility of the value being a different type, and use direct cast otherwise.