C# Stil-Richtlinien

Für jedes Projekt ist es wichtig, klar definierte und konsistente Codierungskonventionen zu haben und Godot ist keine Ausnahme von dieser Regel.

Diese Seite enthält eine Anleitung mit Gestaltungsrichtlinien zum Codieren, dem Entwickler und Mitwirkende von Godot selbst folgen. Als solches ist es hauptsächlich für diejenigen gedacht, die zu dem Projekt beitragen möchten. Da die in diesem Artikel erwähnten Konventionen und Richtlinien jedoch von den Benutzern der Sprache am häufigsten übernommen werden, empfehlen wir Ihnen dasselbe zu tun, insbesondere wenn Sie bisher noch keinen solchen Leitfaden hatten.

Bemerkung

Dieser Artikel ist keineswegs eine vollständige Anleitung zur Befolgung der Standardcodierungskonventionen oder Best Practices. Wenn Sie sich bei einem der hier behandelten Aspekt nicht sicher sind, lesen Sie bitte eine umfassendere Dokumentation, z.B. C# Codierungskonventionen oder Framework Designrichtlinien.

Sprachspezifisch

Godot verwendet derzeit C# Version 7.0 in seiner Engine und im Beispielquellcode. Bevor wir zu einer neueren Version wechseln muss darauf geachtet werden, dass keine Sprachfunktionen gemischt werden, die nur in C# 7.1 oder höher verfügbar sind.

Ausführliche Informationen zu C# Funktionen in verschiedenen Versionen finden Sie unter Was ist neu in C#.

Formatierung

Generelle Richtlinien

  • Nutze Line Feed (LF) zum Zeilenumbruch, nicht CRLF oder CR.
  • Benutze ein Line Feed am Ende jeder Datei, mit Ausnahme der csproj Datei.
  • Verwenden Sie die UTF-8 -Codierung ohne eine Byte order mark.
  • Es sollten 4 Leerzeichen anstelle von Tabulatoren zum Einrücken (die als "weiche Tabulatoren" bezeichnet werden) verwendet werden.
  • Wenn eine Zeile länger als 100 Zeichen ist, sollte sie in mehrere Zeilen aufgeteilt werden.

Zeilenumbrüche und Leerzeilen

Befolgen Sie für eine allgemeine Einrückungsregel den "Allman-Stil" <https://en.wikipedia.org/wiki/Indentation_style#Allman_style>`_ welcher empfiehlt, die mit einer Steueranweisung verknüpfte Klammer in der nächsten Zeile zu platzieren, mit der gleichen Einrückungsstufe:

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

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

Wie auch immer, es sollten Zeilenumbrüche innerhalb von Klammern vermieden werden:

  • Für einfache Zugriffsfunktionen (Property Accessors).
  • Für einfache Objekte, Arrays oder Collection Initializer.
  • Für abstrakte automatische Eigenschaften, Indexer oder selbst Deklarationen.
// 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};
        }
    }
}

eine leere Zeile einfügen:

  • Nach einer Liste von using-Anweisungen.
  • Zwischen Methoden, Eigenschaften und innerer Typen-Deklarationen.
  • Am Ende jeder Datei.

Feld- und Konstantendeklarationen können nach Relevanz gruppiert werden. In diesem Fall sollten Sie eine leere Zeile zwischen den Gruppen einfügen, um das Lesen zu erleichtern.

Vermeide Leerzeilen einzufügen:

  • Nach {, der öffnenden Klammer.
  • Vor }, der schließenden Klammer.
  • Nach einem Kommentar-Block oder einem einzeiligem Kommentar.
  • Angrenzend an eine weitere Leerzeile.
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()
    {
    }
}

Verwendung von Leerzeichen

Leerzeichen einfügen:

  • Um binäre und tertiäre Operatoren.
  • Zwischen einer öffnenden Klammer und if, for, foreach, catch, while, lock oder using Schlüsselwörtern.
  • Vor und innerhalb eines Zugriffsblocks in einer einzelnen Zeile.
  • Zwischen Zugriffsfunktionen in einem einzeiligen Zugriffsblock.
  • Nach einem Komma das nicht am Ende der Zeile steht.
  • Nach einem Semikolon in einer for Statement.
  • Nach einem Doppelpunkt in einem einzelnen case Statement.
  • Um einem Doppelpunkt in einer Typ Deklaration.
  • Um den Lambda Pfeil.
  • Nach einem einzeiligem Kommentar-Symbol (//) und bevor es am Ende einer Zeile genutzt wird.

Nutze kein Leerzeichen:

  • Nach Typ Cast Klammern.
  • Innerhalb einzeiliger Initialisierungsklammern.

Das folgende Beispiel zeigt eine ordnungsgemäße Verwendung von Leerzeichen gemäß einigen der oben genannten Konventionen:

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.
    }
}

Benennungsrichtlinien

Verwenden Sie PascalCase für alle Namensräume, Typnamen und Kennungen auf Elementebene (also Methoden, Eigenschaften, Konstanten, Ereignisse), außer für private Felder:

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

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

Verwenden Sie camelCase für alle anderen Bezeichner (also lokale Variablen, Methodenargumente) und einen Unterstrich (_) als Präfix für private Felder (jedoch nicht für Methoden oder Eigenschaften, wie oben erläutert):

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

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

    targetFound?.Hit(attackStrength);
}

Es gibt eine Ausnahme mit Akronymen die aus zwei Buchstaben bestehen wie UI, die in Großbuchstaben geschrieben werden sollten, wo PascalCase erwartet werden würde und ansonsten in Kleinbuchstaben.

Beachten Sie, dass id kein Akronym ist, daher sollte es als normaler Bezeichner behandelt werden:

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

Es wird allgemein davon abgeraten, einen Typnamen als Präfix eines Bezeichners zu verwenden, wie z. B. string strText oder float fPower. Eine Ausnahme wird jedoch für Schnittstellen gemacht, denen tatsächlich der Großbuchstabe I vor ihren Namen vorangestellt werden sollte, z.B. IInventoryHolder oder IDamageable.

Erwägen Sie schließlich die Auswahl beschreibender Namen und versuchen Sie nicht, diese zu stark zu kürzen, wenn dies die Lesbarkeit beeinträchtigt.

Wenn Sie beispielsweise Code schreiben möchten, um einen nahe gelegenen Feind zu finden und ihn mit einer Waffe zu treffen, bevorzugen Sie:

FindNearbyEnemy()?.Damage(weaponDamage);

besser als:

FindNode()?.Change(wpnDmg);

Mitgliedsvariablen

Deklarieren Sie keine Mitgliedsvariablen, wenn sie nur lokal in einer Methode verwendet werden, da dies das Lesen des Codes erschwert. Deklarieren Sie sie stattdessen als lokale Variablen in der Methode.

Lokale Variablen

Deklarieren Sie lokale Variablen so nah wie möglich am Platz ihrer ersten Verwendung. Dies erleichtert das Lesen des Codes, ohne zu viel scrollen zu müssen, um herauszufinden, wo die Variable deklariert wurde.

Implizit typisierte lokale Variablen

Erwägen Sie die implizite Typisierung (var) für die Deklaration einer lokalen Variablen, aber tun Sie dies nur, wenn der Typ ersichtlich ist (auf der rechten Seite der Zuweisung ):

// 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;

Andere Überlegungen

  • Verwenden Sie explizite Zugriffsmodifikatoren.
  • Verwenden Sie Eigenschaften anstelle von nicht privaten Feldern.
  • Verwenden Sie Modifikatoren in dieser Reihenfolge: public/protected/private/internal/virtual/override/abstract/new/static/readonly.
  • Vermeiden Sie die Verwendung vollständig qualifizierter Namen oder des Präfixes this. für Mitglieder, wenn dies nicht erforderlich ist.
  • Entfernen Sie nicht verwendete using-Anweisungen und unnötige Klammern.
  • Lassen Sie den Standardanfangswert für einen Typ weg.
  • Verwenden Sie möglicherweise nullbedingte Operatoren (null-conditional) oder Typinitialisierer, um den Code kompakter zu gestalten.
  • Verwenden Sie einen sicheren Cast, wenn die Möglichkeit besteht, dass der Wert ein anderer Typ ist und verwenden Sie andernfalls einen direkten Cast.