Up to date

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

C#-Styleguide

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

Diese Seite enthält eine Code-Styleguide, der von den Entwicklern von Godot und denjenigen, die zu Godot selbst beitragen, befolgt wird. 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 meisten Benutzern der Sprache übernommen wurden, möchten wir Sie ermutigen, dasselbe zu tun, insbesondere wenn Sie noch keinen solchen Leitfaden haben.

Bemerkung

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

Sprachspezifikation

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 Sprachfeatures 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

  • Verwenden Sie Line Feed (LF) für Zeilenumbrüche, nicht CRLF oder CR.

  • Verwenden Sie einen Zeilenumbruch am Ende jeder Datei, mit Ausnahme der csproj Datei.

  • Verwenden Sie die UTF-8-Codierung ohne eine Byte order mark.

  • Verwenden Sie 4 Leerzeichen statt Tabulatoren zum Einrücken (dies wird als "weiche Tabulatoren" bezeichnet).

  • Erwägen Sie, eine Zeile in mehrere Zeilen aufzuteilen, wenn sie länger als 100 Zeichen ist.

Zeilenumbrüche und Leerzeilen

Als allgemeine Einrückungsregel gilt der "Allman-Stil", der empfiehlt, die zu einer Steueranweisung gehörende geschweifte Klammer in die nächste Zeile zu setzen, und zwar auf der gleichen Ebene eingerückt:

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

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

Sie können jedoch auch Zeilenumbrüche innerhalb von Klammern weglassen:

  • Für einfache Property-Zugriffsfunktionen.

  • Für einfache Objekt-, Array- oder Collection Initializer.

  • Für abstrakte Auto-Property-, Indexer- oder Event-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};
        }
    }
}

Fügen Sie eine Leerzeile ein:

  • Nach einer Liste von using-Anweisungen.

  • Zwischen Methoden, Propertys und inneren Typ-Deklarationen.

  • Am Ende jeder Datei.

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

Vermeiden Sie, 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

Fügen Sie ein Leerzeichen ein:

  • Um einen binären und tertiären Operator.

  • Zwischen einer öffnenden Klammer und if, for, foreach, catch, while, lock oder using-Schlüsselwörtern.

  • Vor und innerhalb eines einzeiligen Zugriffsblocks.

  • Zwischen Zugriffsfunktionen in einem einzeiligen Zugriffsblock.

  • Nach einem Komma, das nicht am Ende der Zeile steht.

  • Nach einem Semikolon in einer for-Anweisung.

  • Nach einem Doppelpunkt in einer einzeiligen case-Anweisung.

  • Um einen Doppelpunkt in einer Typ-Deklaration.

  • Um einen Lambda-Pfeil.

  • Nach einem einzeiligen Kommentar-Symbol (//) und davor, wenn es am Ende einer Zeile genutzt wird.

Verwenden Sie kein Leerzeichen:

  • Nach Typ-Cast-Klammern.

  • Innerhalb einzeiliger Initialisierer-Klammern.

Das folgende Beispiel zeigt die korrekte 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.
    }
}

Namenskonventionen

Verwenden Sie PascalCase für alle Namespaces, Typnamen und Bezeichner auf Member-Ebene (d.h. Methoden, Propertys, Konstanten, Events), 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 (d.h. lokale Variablen, Methodenargumente), verwenden Sie einen Unterstrich (_) als Präfix für private Felder (jedoch nicht für Methoden oder Propertys, 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);
}

Eine Ausnahme bilden Akronyme, die aus zwei Buchstaben bestehen, wie z.B. UI, die dort, wo PascalCase erwartet wird, in Großbuchstaben und ansonsten in Kleinbuchstaben geschrieben werden sollten.

Beachten Sie, dass id kein Akronym ist, daher sollte es wie ein 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 Interfaces gemacht, denen tatsächlich der Großbuchstabe I vor ihren Namen vorangestellt werden sollte, z.B. IInventoryHolder oder IDamageable.

Schließlich sollten Sie beschreibende Namen wählen und nicht versuchen, sie zu sehr zu kürzen, wenn dies die Lesbarkeit beeinträchtigt.

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

FindNearbyEnemy()?.Damage(weaponDamage);

Besser als:

FindNode()?.Change(wpnDmg);

Membervariablen

Deklarieren Sie keine Membervariablen, 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 Ort 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 offensichtlich 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;

Weitere Überlegungen

  • Verwenden Sie explizite Zugriffsmodifikatoren.

  • Verwenden Sie Propertys 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 Member, wenn dies nicht erforderlich ist.

  • Entfernen Sie nicht verwendete using-Anweisungen und unnötige Klammern.

  • Lassen Sie den Default-Initialwert für einen Typ weg.

  • Erwägen Sie die Verwendung von Null-Bedingungsoperatoren oder Typinitialisierern, 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.