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

Godot currently uses C# version 7.0 in its engine and example source code. So, before we move to a newer version, care must be taken to avoid mixing language features only available in C# 7.1 or later.

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

  • Use line feed (LF) characters to break lines, not CRLF or CR.
  • Use UTF-8 encoding without a byte order mark.
  • Use 4 spaces instead of tabs for indentation (which is referred to as « soft tabs »).
  • Consider breaking a line into several if it’s longer than 100 characters.

Retours de ligne et lignes vierges

For a general indentation rule, follow the « Allman Style » which recommends placing the brace associated with a control statement on the next line, indented to the same level:

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

  • After a list of using statements.
  • 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 }.
  • After a comment block or a single-line comment.
  • 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.
  • Between an opening parenthesis and if, for, foreach, catch, while, lock or using keywords.
  • 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.
  • After a semicolon in a for statement.
  • After a colon in a single line case statement.
  • Autour d’un deux-points dans une déclaration de type.
  • Autour d’une flèche lambda.
  • After a single-line comment symbol (//), and before it if used at the end of a line.

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

Use PascalCase for all namespaces, type names and member level identifiers (i.e. methods, properties, constants, events), except for private fields:

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

        public float CurrentSpeed { get; set; }

        protected int HitPoints;

        private void CalculateWeaponDamage()
        {
        }
    }
}

Use camelCase for all other identifiers (i.e. local variables, method arguments), and use an underscore (_) as a prefix for private fields (but not for methods or properties, as explained above):

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

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

    targetFound?.Hit(attackStrength);
}

There’s an exception with acronyms which consist of two letters, like UI, which should be written in uppercase letters where PascalCase would be expected, and in lowercase letters otherwise.

Note that id is not an acronym, so it should be treated as a normal identifier:

public string Id { get; }

public UIManager UI
{
    get { return uiManager; }
}

It is generally discouraged to use a type name as a prefix of an identifier, like string strText or float fPower, for example. An exception is made, however, for interfaces, which should, in fact, have an uppercase letter I prefixed to their names, like IInventoryHolder or IDamageable.

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

For instance, if you want to write code to find a nearby enemy and hit it with a weapon, prefer:

FindNearbyEnemy()?.Damage(weaponDamage);

Rather than:

FindNode()?.Change(wpnDmg);

Variables locales implicitement typées

Consider using implicitly typing (var) for declaration of a local variable, but do so only when the type is evident from the right side of the assignment:

// 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.
  • Use modifiers in this order: public/protected/private/internal/virtual/override/abstract/new/static/readonly.
  • Avoid using fully-qualified names or this. prefix for members when it’s not necessary.
  • Remove unused using statements and unnecessary parentheses.
  • Consider omitting the default initial value for a 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.