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 6.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.0 ou plus, comme le filtrage par expression ou les définitions de corps d’expression à l’intérieur des accesseurs get/set.

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

Conventions de formatage

  • Si vous créez un nouveau fichier, assurez-vous qu’il utilise le caractères de saut de ligne (LF) pour les retours à la ligne, et non CRLF ou CR.
  • Utilisez l’encodage UTF-8 sans indicateur d’ordre d’octet (BOM <https://fr.wikipedia.org/wiki/Indicateur_d%27ordre_des_octets>).
  • Utilisez 4 espaces au lieu de tabulations pour l’indentation (ce que l’on appelle les “soft tabs”).

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 utilisation de la liste des instructions.
  • Entre les déclarations de méthodes, de propriétés, et de types internes.
  • At the end of each file.

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;
    private Vector3 _y;                       // Related constants or fields can be
                                              // 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()
    {
    }
}

Consider breaking a line when it’s longer than 100 characters.

Ensure that all lines use the Unix LF format, not CRLF.

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.
  • Après un point-virgule dans une instruction for.
  • Après un deux-points dans une instruction case d’une ligne.
  • 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 '_' 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. Cependant, il y a une exception à propos des interfaces, cas où elles devraient être nommées en utilisant un préfixe “I” majuscule , 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 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 '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.