Guide de style C#

Avoir des conventions de codage bien définies et cohérentes est important pour chaque projet, et Godot ne fait pas exception à cette règle.

Cette page contient un guide de style de codage qui est suivi par les développeurs et les contributeurs de Godot lui-même. En tant que tel, il est principalement destiné à ceux qui veulent contribuer au projet, mais comme les conventions et directives mentionnées dans cet article sont celles qui sont les plus largement adoptées par les utilisateurs du langage, nous vous encourageons à faire de même, surtout si vous n'avez pas encore un tel guide.

Note

Cet article n'est en aucun cas un guide exhaustif sur la façon de suivre les conventions de codage standard ou les meilleures pratiques. Si vous n'êtes pas sûr d'un aspect qui n'est pas couvert ici, veuillez vous référer à une documentation plus complète, telle que Conventions de codage C# ou Règles de conception de .NET Framework.

Spécification du langage

Actuellement, Godot utilise C# version 7.0 dans son moteur et son code source d'exemple. Ainsi, avant de passer à une nouvelle version, il faut prendre soin d'éviter de mélanger des fonctionnalités de langage disponibles uniquement en C# 7.1 ou plus.

Pour des informations détaillées sur les fonctionnalités C# dans différentes versions, veuillez consulter Quoi de neuf en C#.

Formatage

Lignes directrices générales

  • Utilisez le saut de ligne (LF) pour briser les lignes, et non CRLF ou CR.
  • Utilisez un caractère de saut de ligne à la fin de chaque fichier, sauf pour les fichiers csproj.
  • Utilisez l'encodage UTF-8 sans marque d'ordre d'octet.
  • Utilisez 4 espaces au lieu de tabulations pour l'indentation (ce que l'on appelle les "soft tabs" ou "tabulation douce" :)).
  • Si une ligne compte plus de 100 caractères, on peut envisager de la diviser en plusieurs lignes.

Retours de ligne et lignes vierges

Pour une règle générale d'indentation, suivez le style d'indentation d'Allman qui recommande de placer l'accolade associée à une instruction de contrôle sur la ligne suivante, indentée au même niveau :

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

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

Cependant, vous pouvez choisir d'omettre les sauts de ligne entre accolades :

  • Pour les accesseurs de propriétés simples.
  • Pour les initialisateurs d'objets simples, de tableaux ou de collections.
  • Pour la propriété automatique abstraite, l'indexeur ou les déclarations d'événements.
// 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};
        }
    }
}

Insérez une ligne vierge :

  • Après une liste d'instruction using.
  • Entre les déclarations de méthodes, de propriétés, et de types internes.
  • A la fin de chaque fichier.

Les déclarations de champs et de constantes peuvent être regroupées en fonction de leur pertinence. Dans ce cas, envisagez d'insérer une ligne blanche entre les groupes pour faciliter la lecture.

Évitez d'insérer une ligne blanche :

  • Après une accolade ouvrante {.
  • Avant une accolade fermante }.
  • Après un bloc de commentaires, ou un commentaire d'une seule ligne.
  • Adjacente à une autre ligne vide.
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()
    {
    }
}

Utilisation des espaces

Insérez un espace :

  • Autour d'un opérateur binaire et tertiaire.
  • Entre une parenthèse ouvrante et les mots-clés if, for, foreach, catch, while, lock ou using.
  • Avant et au sein d’un bloc d’accesseur tenant sur une seule ligne.
  • Entre accesseurs dans un bloc d’accesseurs sur une seule ligne.
  • Après une virgule qui n'est pas en fin de ligne.
  • Après un point-virgule dans une boucle for.
  • Après un deux-points dans une instruction case longue d'une ligne uniquement.
  • Autour d'un deux-points dans une déclaration de type.
  • Autour d'une flèche lambda.
  • Après le symbole de commentaire d'une seule ligne ('//'), et avant si celui-ci est utilisé à la fin d'une ligne.

N'utilisez pas d'espace :

  • Après les parenthèses de conversion de type.
  • Dans les accolades d'initialisation monoligne.

L'exemple suivant montre une utilisation correcte des espaces, selon certaines des conventions mentionnées ci-dessus :

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

Conventions de nommage

Utilisez le PascalCase pour tous les espaces de noms, les noms de type et les identificateurs de niveau membre (c.-à-d. méthodes, propriétés, constantes, événements), sauf pour les champs privés :

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

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

Utilisez le camelCase pour tous les autres identificateurs (i.e. variables locales, arguments de méthode), et utilisez le trait de soulignement ('_') comme préfixe pour les champs privés (mais pas pour les méthodes ou propriétés, comme expliqué ci-dessus) :

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

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

    targetFound?.Hit(attackStrength);
}

Il y a une exception avec les acronymes qui consistent en deux lettres comme UI qui devrait être écrit en lettres majuscules lorsqu'ils sont utilisés là où la casse Pascal serait attendue, et en lettres minuscules sinon.

Notez que id n'est pas un acronyme, il doit donc être traité comme un identificateur normal :

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

Il est généralement déconseillé d'utiliser un nom de type comme préfixe d'un identificateur, comme string strText ou float fPower, par exemple. Une exception est toutefois faite pour les interfaces, qui devraient, en fait, avoir une lettre majuscule I préfixée à leur nom, comme IInventoryHolder ou IDamageable.

Enfin, pensez à choisir des noms descriptifs et n'essayez pas de les raccourcir trop si cela affecte la lisibilité.

Par exemple, si vous voulez écrire un code pour trouver un ennemi proche et le frapper avec une arme, préférez :

FindNearbyEnemy()?.Damage(weaponDamage);

Plutôt que :

FindNode()?.Change(wpnDmg);

Variables membres

Ne déclarez pas les variables membres si elles ne sont utilisées que localement dans une méthode, car cela rend le code plus difficile à suivre. Déclarez-les plutôt comme des variables locales dans le corps de la méthode.

Variables locales

Déclarez les variables locales le plus près possible de leur première utilisation. Il est ainsi plus facile de suivre le code, sans avoir à trop le faire défiler pour retrouver l'endroit où la variable a été déclarée.

Variables locales implicitement typées

Envisagez d'utiliser la saisie implicite (var) pour la déclaration d'une variable locale, mais faites-le seulement lorsque le type est évident du côté droit de l'assignation :

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

Autres considérations

  • Utilisez des modificateurs d'accès explicites.
  • Utilisez des propriétés au lieu de champs non privés.
  • Utilisez les modificateurs dans cet ordre : public/protected/private/internal/virtual/override/abstract/new/static/readonly.
  • Évitez d'utiliser des noms complets ou le préfixe this. pour les membres lorsque ce n'est pas nécessaire.
  • Enlevez les instructions using non utilisées et les parenthèses non nécessaires.
  • Envisagez d'omettre la valeur initiale par défaut pour un type.
  • Envisagez d'utiliser des opérateurs conditionnels null ou des initialisateurs de type pour rendre le code plus compact.
  • Utilisez un safe cast lorsqu'il y a une possibilité que la valeur soit d'un type différent, et utilisez un cast direct dans le cas contraire.