Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Руководство по стилю C#

Наличие четко определенных и согласованных соглашений о программировании важно для каждого проекта, и Godot не является исключением из этого правила.

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

Примечание

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

Спецификация языка

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

Для получения подробной информации о возможностях C# в различных версиях см. Что нового в C#.

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

Общие рекомендации

  • Для перевода строки используйте символы перевода строки (LF), а не CRLF или CR.

  • Используйте один символ перевода строки в конце каждого файла, за исключением файлов csproj.

  • Используйте кодировку UTF-8 без маркера последовательности байтов.

  • Используйте 4 пробела вместо табов для отступа (которые называются «мягкими табами»).

  • Попробуйте разбить строку на несколько, если она длиннее 100 символов.

Разрывы строки и пустые строки

Для общего правила отступа следуйте " стилю Олмана ", который рекомендует размещать фигурную скобку, связанную с оператором управления, на следующей строке, с отступом к тому же уровню:

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

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

Однако вы можете пропустить разрывы строк внутри скобок:

  • Для простых методов доступа к свойствам.

  • Для простых инициализаторов объектов, массивов или коллекций.

  • Для абстрактного автоматического свойства, индексатора или объявлений событий.

// 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()
    {
    }
}

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

Вставьте пробел:

  • Around a binary and ternary operator.

  • Между открывающей скобкой и ключевыми словами if, for, foreach, catch, while, lock или using.

  • До и внутри однострочного блока доступа.

  • Между аксессорами в однострочном блоке аксессоров.

  • После запятой, которая не находится в конце строки.

  • После точки с запятой в выражении 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);

Переменные-члены

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

Локальные переменные

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

Неявно типизированные локальные переменные

Попробуйте использовать неявную типизацию (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;

Другие соображения

  • Используйте явные модификаторы доступа.

  • Используйте свойства вместо не закрытых полей.

  • Используйте модификаторы в следующем порядке: public / protected / private / internal / virtual / override / abstract / new / static / readonly.

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

  • Удалите неиспользуемые операторы using и лишние скобки.

  • Попробуйте пропустить начальное значение по умолчанию для типа.

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

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