Menu

Variables en C# : var, const, readonly, portée et nommage

Comment déclarer et affecter des variables en C#, quand var est une bonne idée et quand il ne l'est pas, comment fonctionne la portée, la différence entre const, readonly et static readonly, les conventions de nommage et l'erreur de variable non assignée.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Une variable est un emplacement de stockage nommé, avec un type fixe. En C#, on la déclare avec un type et un nom, et on peut lui donner une valeur dans la même instruction. Le type ne change jamais ensuite : une variable int contient des nombres entiers tant qu'elle existe.

Sortie :

Priya bought 5 items for 20.25
10

Affecter une valeur du mauvais type est une erreur de compilation : quantity = "five"; échoue avec CS0029 (cannot implicitly convert type 'string' to 'int'). Les conversions entre types sont explicites ; voir conversion de types.

var : laisser le compilateur déduire le type

var déclare une variable locale dont le type est déduit de son initialiseur. Ce n'est pas du typage dynamique : le type est fixé à la compilation, exactement comme si vous l'aviez écrit.

Sortie :

String
Int32
Decimal
Double
List`1

var obéit à trois règles. Il ne fonctionne que pour les variables locales (pas les champs ni les paramètres). La variable doit être initialisée dans la déclaration : var x; donne l'erreur CS0818, « Implicitly-typed variables must be initialized ». Et l'initialiseur doit avoir un type : var nothing = null; ne compile pas, car null seul n'a pas de type.

Quand l'utiliser relève du style de l'équipe. La règle habituelle est d'utiliser var quand le type est évident d'après la partie droite, et d'écrire le type quand il ne l'est pas :

var orders = new List<Order>();         // obvious: var is fine
var reader = new StreamReader(path);    // obvious
decimal discount = CalculateDiscount(); // not obvious: name the type
int count = items.Count();              // makes the intent clear

Un piège subtil : var total = 0; fait de total un int, donc lui ajouter 2.5 plus tard échoue, et var price = 10; est un int, pas un decimal. Quand le type du littéral n'est pas celui que vous voulez, écrivez le type ou ajoutez un suffixe (10m, 0.0).

La portée

Une variable locale existe de sa déclaration jusqu'à la fin du bloc { } dans lequel elle a été déclarée. Les variables déclarées dans l'en-tête d'une boucle ou dans le corps d'un if ne sont plus visibles après.

Sortie :

high
240

Contrairement à C et C++, C# ne permet pas à un bloc interne de déclarer une variable locale portant le même nom qu'une variable d'un bloc englobant (erreur CS0136) : un nom doit désigner une seule chose dans toute la méthode. Deux blocs voisins peuvent réutiliser un nom, comme le font deux boucles for distinctes qui déclarent chacune i.

L'affectation définie

Les variables locales n'ont pas de valeur par défaut. Le compilateur suit chaque chemin de la méthode et refuse de compiler si une variable risque d'être lue avant d'avoir été affectée :

int discount;
if (isMember)
{
    discount = 10;
}
Console.WriteLine(discount);
// error CS0165: Use of unassigned local variable 'discount'

Corrigez en initialisant à la déclaration (int discount = 0;) ou en affectant dans chaque branche (ajoutez un else). Les champs et les éléments de tableau sont différents : ils reçoivent automatiquement la valeur par défaut de leur type (0, false, null).

const : les constantes de compilation

Un const est une valeur fixée à la compilation. Il doit être initialisé avec une expression constante (un littéral, un autre const, ou une opération arithmétique sur ceux-ci), et ne peut être qu'un nombre, un char, un bool, une string, un enum ou null.

Sortie :

Price in EUR
120.00 EUR
350

Un champ const est implicitement static : on y accède par le nom du type (Pricing.VatRate), et écrire static const est une erreur. Le compilateur copie la valeur à chaque endroit qui l'utilise, c'est pourquoi les consts ne coûtent rien à l'exécution, et aussi pourquoi un const public dans une bibliothèque doit être une valeur qui ne changera jamais (comme le nombre de jours dans une semaine).

readonly et static readonly

Un champ readonly ne peut être affecté que dans sa déclaration ou dans un constructeur de sa classe. Après la construction, il ne peut plus changer. Contrairement à const, sa valeur est calculée à l'exécution, peut être de n'importe quel type et peut différer d'un objet à l'autre.

Sortie :

ACC-17 opened 2024-05-02
Launch: 2020-01-15
basic, pro

Les dernières lignes montrent le malentendu courant : readonly protège le champ, pas l'objet vers lequel il pointe. Plans désignera toujours le même tableau, mais les éléments du tableau peuvent encore changer. Pour des collections vraiment immuables, utilisez ReadOnlyCollection<T> ou ImmutableArray<T>.

Récapitulatif des trois :

constreadonlystatic readonly
Valeur connueÀ la compilationÀ l'exécutionÀ l'exécution
Types autorisésNombres, char, bool, string, enums, nullTousTous
Défini dansLa déclaration uniquementLa déclaration ou un constructeurLa déclaration ou le constructeur statique
Par objet ou partagéPartagé (implicitement statique)Par objetPartagé
Variables localesOui (const int x = 1;)NonNon

Conventions de nommage

Les noms C# sont sensibles à la casse (total et Total sont des variables différentes) et doivent commencer par une lettre ou un underscore. Les conventions de Microsoft, suivies par presque tout le code C# :

  • Variables locales et paramètres : camelCase (orderCount, unitPrice).
  • Constantes, propriétés, méthodes, classes et champs publics : PascalCase (MaxItems, VatRate).
  • Champs privés : _camelCase avec un underscore initial (_balance), une convention très répandue dans le code .NET.
  • Les booléens se lisent comme des questions : isActive, hasDiscount, canRetry.
  • Évitez les abréviations et les préfixes hongrois (strName, iCount).

Un mot-clé C# ne peut pas servir de nom, sauf si vous le préfixez par @ : var @class = "5B"; est légal, ce qui sert parfois pour du code généré ou des noms de champs JSON.

Échange et affectation multiple

Depuis C# 7, les tuples permettent d'affecter plusieurs variables en une seule instruction, ce qui donne un échange en une ligne :

Sortie :

20 10
Lisbon: 545,000

La seconde forme est une déconstruction : elle déclare city comme string et population comme int à partir d'un tuple. Plus de détails dans tuples.

Questions fréquentes

Qu'est-ce que var en C# ?

var demande au compilateur de déduire le type d'une variable locale à partir de la valeur qui l'initialise : var count = 5; déclare un int. La variable reste typée statiquement et ne pourra pas contenir une chaîne plus tard. var ne fonctionne que pour les variables locales initialisées dans la même instruction.

Quelle est la différence entre const et readonly en C# ?

Un const est une constante de compilation : sa valeur doit être connue à la compilation (nombres, chaînes, bool, null), il est implicitement statique, et la valeur est copiée à chaque endroit qui l'utilise. Un champ readonly est défini une seule fois à l'exécution, dans sa déclaration ou dans un constructeur, peut contenir n'importe quel type et peut différer d'un objet à l'autre.

Quand utiliser static readonly plutôt que const ?

Utilisez static readonly pour une valeur partagée qui ne peut pas être une constante de compilation, comme un DateTime, un tableau ou un objet, ou pour une valeur publique susceptible de changer d'une version d'une bibliothèque à l'autre. Comme les valeurs const sont copiées dans les assemblies appelants, modifier un const public oblige à recompiler tous les assemblies qui l'utilisent.

Que signifie « use of unassigned local variable » en C# ?

Erreur CS0165 : le compilateur a trouvé un chemin où une variable locale est lue avant qu'une valeur lui ait été affectée. Les variables locales n'ont pas de valeur par défaut en C#. Initialisez la variable à sa déclaration, ou assurez-vous que chaque branche du if/switch l'affecte avant son utilisation.

Faut-il utiliser var ou des types explicites en C# ?

Les deux conviennent ; les équipes choisissent un style. Une règle courante consiste à utiliser var quand le type est évident d'après la partie droite (var list = new List<string>();) et à écrire le type quand il ne l'est pas (decimal total = GetTotal();). Le code du runtime .NET suit à peu près cette règle.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER