Menu

Paramètres optionnels et arguments nommés en C# : valeurs par défaut et règles

Comment fonctionnent les paramètres optionnels et les arguments nommés en C# : valeurs par défaut et règle de la constante de compilation, ordre des paramètres, sauter des arguments par leur nom, paramètres optionnels ou surcharges, attributs d'information sur l'appelant, et le piège de version des valeurs par défaut figées chez l'appelant.

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

Un paramètre optionnel a une valeur par défaut dans la déclaration de la méthode, les appelants peuvent donc l'omettre. Un argument nommé passe une valeur par le nom du paramètre au lieu de sa position. Ensemble, ils permettent à une seule méthode de servir de nombreuses formes d'appel sans une pile de surcharges.

Sortie :

to ana@mail.com: (no subject), retries 3
to ben@mail.com: Invoice #1042, retries 3
to cy@mail.com: (no subject) [URGENT], retries 3
to dev@mail.com: Build failed, retries 0

Le troisième appel saute subject et définit urgent par son nom ; sans arguments nommés, il faudrait repasser "(no subject)" juste pour atteindre la troisième position. Le dernier appel passe chaque argument par son nom, dans un ordre différent de la déclaration, ce qui est légal.

Règles pour les valeurs par défaut

Une valeur par défaut doit être quelque chose que le compilateur peut calculer :

  • une constante (3, "INFO", true, 1.5m, un champ const, un membre d'enum)
  • null pour un type référence ou nullable
  • default(T), ou new T() pour un type valeur T

Tout ce qui est évalué à l'exécution est refusé. Le cas classique est une date :

static void Schedule(string task, DateTime at = DateTime.Now) { }
// error CS1736: Default parameter value for 'at' must be a compile-time constant

Le contournement standard est un paramètre nullable avec null pour valeur par défaut, résolu dans le corps :

Sortie :

backup at 2026-01-01 09:00, tags: 0
report at 2026-03-15 18:30, tags: 0
deploy at 2026-01-01 09:00, tags: 2

La même astuce vaut pour les collections : une valeur par défaut new List<string>() n'est pas une constante, donc mettez null par défaut et créez la liste à l'intérieur. Cela évite aussi le bug, à la Python, de la valeur par défaut modifiable partagée, que C# exclut en n'autorisant que des constantes.

Règles d'ordre

Les paramètres obligatoires viennent en premier, les optionnels ensuite, et un tableau params (s'il y en a un) en dernier :

static void Log(string message, string level = "INFO", params string[] tags) { }   // OK

static void Log(string level = "INFO", string message) { }
// error CS1737: Optional parameters must appear after all required parameters

Les paramètres ref et out ne peuvent pas être optionnels.

Côté appel, les arguments positionnels remplissent les paramètres depuis le début. Les arguments nommés peuvent les suivre dans n'importe quel ordre. Depuis C# 7.2, un argument nommé peut aussi apparaître avant un argument positionnel, mais seulement s'il est à sa propre position (SendEmail("a@b.c", subject: "Hi", true)) ; dans les versions plus anciennes, les arguments nommés doivent tous venir en dernier. Omettre un paramètre obligatoire, même en nommant les autres, est une erreur de compilation.

Des arguments nommés pour la lisibilité

Les arguments nommés sont utiles même quand rien n'est optionnel. Des true, false, null littéraux et des nombres nus ne disent rien à l'endroit de l'appel :

ResizeImage(photo, 800, 600, true, false);                                   // which is which?
ResizeImage(photo, width: 800, height: 600, keepAspect: true, upscale: false);

Renommer un paramètre devient un changement cassant pour les appelants qui utilisent le nom, ce qu'il vaut mieux garder en tête dans une bibliothèque publique.

Paramètres optionnels ou surcharges

Avant C# 4, la même souplesse demandait une surcharge par combinaison. Les paramètres optionnels les regroupent en une seule méthode :

// overloads
static void Connect(string host) => Connect(host, 443);
static void Connect(string host, int port) => Connect(host, port, 30);
static void Connect(string host, int port, int timeoutSeconds) { /* ... */ }

// one method with optional parameters
static void Connect(string host, int port = 443, int timeoutSeconds = 30) { /* ... */ }

Quand les deux existent, la résolution de surcharge préfère un candidat qui n'a besoin d'aucune valeur par défaut :

Sortie :

Greet()
Greet(string) with Lena

Greet() correspond aux deux méthodes, et le compilateur choisit celle qui n'omet aucun paramètre optionnel. Mélanger les deux techniques sur un même nom produit surtout des appels dont la cible est difficile à prévoir ; choisissez-en donc une par méthode.

Choisissez les surcharges quand les variantes demandent un code ou des types de paramètres différents, et les paramètres optionnels quand elles ne diffèrent que par les valeurs par défaut.

Les valeurs par défaut sont figées chez l'appelant

Une valeur par défaut n'est pas recherchée à l'exécution. Le compilateur la copie dans chaque site d'appel lors de la compilation du code appelant. Connect("api.shop.com") se compile en Connect("api.shop.com", 443, 30).

Cela a une conséquence pour les bibliothèques. Supposons que la version 1 d'un package fournisse Connect(string host, int timeoutSeconds = 30) et que la version 2 change la valeur par défaut en 10. Une application compilée avec la version 1 continue de passer 30 après que vous avez déposé la DLL de la version 2, jusqu'à ce que l'application elle-même soit recompilée. Ajouter un nouveau paramètre optionnel à une méthode publique existante casse aussi les appelants déjà compilés, car la signature de la méthode a changé et ils cherchent toujours l'ancienne (une MissingMethodException à l'exécution).

Au sein d'une application compilée d'un seul tenant, cela ne compte jamais. Pour les API publiques des packages NuGet, les surcharges (qui gardent les valeurs par défaut dans la bibliothèque) ou une valeur par défaut null résolue dans le corps évitent le problème.

Valeurs par défaut et type déclaré

La même règle de compilation fait que, lorsqu'une interface et une classe déclarent toutes deux des valeurs par défaut, la valeur vient du type de la variable par laquelle vous appelez, pas de l'objet :

Sortie :

printing "report" x5
printing "report" x1

Même objet, deux valeurs par défaut différentes. Gardez des valeurs par défaut identiques entre une interface et ses implémentations, ou déclarez-les à un seul endroit.

Attributs d'information sur l'appelant

Les paramètres optionnels alimentent aussi les attributs d'information sur l'appelant de System.Runtime.CompilerServices. Le compilateur les remplit avec des détails sur le site d'appel :

Sortie :

[Main:18] starting
[SaveOrder:13] order saved

C'est ainsi que les bibliothèques de journalisation enregistrent l'origine d'un message sans que l'appelant ait à la taper, et que les implémentations de INotifyPropertyChanged obtiennent le nom de la propriété. [CallerFilePath] ajoute de la même façon le chemin du fichier source.

Questions fréquentes

Comment rendre un paramètre optionnel en C# ?

Donnez-lui une valeur par défaut dans la déclaration : static void Log(string message, string level = "INFO"). Les appelants peuvent alors écrire Log("started") ou Log("failed", "ERROR"). Les paramètres optionnels doivent venir après tous les paramètres obligatoires, et la valeur par défaut doit être une constante de compilation.

Que sont les arguments nommés en C# ?

Des arguments passés avec le nom du paramètre : SendEmail(to: "ana@mail.com", urgent: true). Ils permettent de sauter des paramètres optionnels au milieu, de passer les arguments dans n'importe quel ordre, et de rendre lisibles d'un coup d'œil les appels avec des true/false littéraux ou des nombres.

Pourquoi ne peut-on pas utiliser DateTime.Now comme valeur par défaut d'un paramètre ?

Les valeurs par défaut doivent être des constantes de compilation, et DateTime.Now est calculé à l'exécution, donc le compilateur signale CS1736, Default parameter value for 'at' must be a compile-time constant. Utilisez plutôt un paramètre nullable : DateTime? at = null, puis DateTime time = at ?? DateTime.Now; dans le corps.

Faut-il utiliser des paramètres optionnels ou des surcharges de méthode en C# ?

Les paramètres optionnels sont plus simples quand les variantes ne diffèrent que par des valeurs par défaut. Les surcharges sont préférables quand les variantes demandent une logique ou des types différents, et dans les bibliothèques publiques, car une valeur par défaut est compilée dans chaque appelant et la modifier plus tard n'atteint pas le code déjà compilé.

Que signifie « Optional parameters must appear after all required parameters » ?

Erreur CS1737 : un paramètre doté d'une valeur par défaut est suivi d'un paramètre qui n'en a pas. Placez d'abord les paramètres obligatoires : (string to, bool urgent = false), et non (bool urgent = false, string to). Après un paramètre optionnel, seuls d'autres paramètres optionnels ou un tableau params peuvent suivre.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER