C#スタイルガイド

明確に定義された一貫したコーディング規約を持つことはすべてのプロジェクトにとって重要であり、Godotも例外ではありません。

このページには、Godot自体の開発者および貢献者が従うコーディングスタイルガイドが含まれています。そのため、主にプロジェクトに貢献したい人を対象としていますが、この記事で言及されている規約とガイドラインはこの言語のユーザーによって最も広く採用されているものなので、特に従うべぎ(チーム内の規定などの)ガイドをまだ持っていない場合は、同じことを行うことをお勧めします。

注釈

この記事は、標準コーディング規約やベスト・プラクティスに従う方法を網羅したガイドではありません。ここで説明していない側面について不明な点がある場合は、 C# Coding Conventions <https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions>Framework Design Guidelines <https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines> など、より包括的なドキュメントを参照してください。

言語仕様

Godotは現在、エンジンとサンプルソースコードで C# バージョン7.0 を使用しています。したがって、新しいバージョンに移行する前に、C# 7.1以降でのみ使用可能な言語機能が混在しないように注意する必要があります。

異なるバージョンのC#機能の詳細については、 `C#の新機能<https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/> ` を参照してください。

書式設定

一般的なガイドライン

  • CRLFやCRではなく、改行(LF)文字を使用して改行します。
  • csproj ファイルを除き、各ファイルの末尾に1つの改行文字を使用します。
  • バイトオーダーマーク<https://en.wikipedia.org/wiki/Byte_order_mark> なしで UTF-8 エンコーディングを使用します。
  • インデントにタブの代わりに 4つのスペース を使用します(「ソフトタブ」と呼ばれます)。
  • 100文字を超える場合は、行を複数に分割することを検討してください。

改行と空白行

一般的なインデントルールについては、"Allman Style"<https://en.wikipedia.org/wiki/Indentation_style#Allman_style> に従って、制御ステートメントに関連付けられたブレースを次の行に配置し、同じレベルにインデントすることをお勧めします。

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

スペースの使用

スペースを挿入する:

  • 二項演算子と三次演算子の周囲。
  • 左括弧と ifforforeachcatchwhilelock 、または 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 のような 2つの文字で構成される頭字語には例外があり、PascalCaseで予期される大文字で記述する必要があります(例:**U**ser**I**nterface → UI)。

id は略語ではないため、通常の識別子として扱う必要があります。

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

一般に、たとえば string strTextfloat fPower のように、識別子のプレフィックスとして型名を使用することは推奨されません。ただし、インターフェイスについては例外が設けれれています。実際には、名前に InventoryHolderIDamageable のように大文字の I が先頭に付いている必要があります。

最後に、わかりやすい名前を選択することを検討し、読みやすさに影響を与える場合は、あまり短くしないでください。

たとえば、近くの敵を見つけて武器で攻撃するコードを作成する場合は、次のよう書きます:

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 ステートメントと不要な括弧を削除します。
  • 型の既定の初期値を省略することを検討してください。
  • コードをよりコンパクトにするために、null条件演算子または型初期化を使用することを検討してください。
  • 値が異なるタイプである可能性がある場合は、セーフキャストを使用し、それ以外の場合は直接キャストを使用します。