This article is currently in the process of being translated into French (~85% done).
Method parameters
Dans le chapitre précédent, nous parlions des méthodes et nous avions introduit le concept de paramètre de méthodes/fonctions. Dans ce chapitre, nous allons entrer dans le détail du sujet sous toutes ses formes. Comme mentionné, les méthodes peuvent fonctionner sans paramètres, mais habituellement ils auront un ou plusieurs paramètres, qui aideront la méthode à accomplir sa tâche.
Nous avons déjà vu un scénario très simple pour les paramètres dans le précédent chapitre: notre méthode AddNumbers() qui prend deux nombres en paramètres et retourne la somme de ces deux nombres.
public int AddNumbers(int number1, int number2)
{
return number1 + number2;
}
Cela montre bien à quel point les méthodes sont un concept intelligent, car avec les méthodes, vous pouvez encapsuler la fonctionnalité dans la méthode, vous êtes en mesure d'affecter le résultat lorsque vous appelez cette méthode par le biais de paramètres :
AddNumbers(2, 3);
Result: 5
AddNumbers(38, 4);
Result: 42
Il s'agit du type de paramètres de base, mais parlons plus en détail des divers modificateurs et options que vous pouvez utiliser pour modifier le comportement des paramètres.
Notez que dans cet article, nous allons vraiment approfondir tous les différents types de paramètres et comment ils peuvent vous aider, mais si vous débutez en C# et que vous voulez juste voir quelques résultats, ce qui suit est peut-être un peu trop complexe et technique pour le moment. N'hésitez pas à sauter le reste de l'article et à revenir plus tard lorsque vous serez prêt.
Paramètres optionnels
Par défaut, lorsque vous appelez une méthode avec un ou plusieurs paramètres, vous êtres obligé de fournir des valeurs pour tous ces paramètres. Toutefois, dans certaines situations, vous pouvez avoir besoin de rendre un ou plusieurs paramètres facultatifs. Dans certains langages de programmation, vous pourriez le faire simplement en marquant le paramètre comme facultatif, mais en C#, un paramètre est re du facultatif en fournissant une valeur par défaut dans la déclaration de la méthode. C'est en fait une solution intéressante, car elle vous évite d'écrire du code supplémentaire pour gérer les situations où le paramètre n'est pas fourni par l'appelant.
Voici un exemple de méthode avec un paramètre optionnel:
public int AddNumbers(int number1, int number2, int number3 = 0)
{
return number1 + number2 + number3;
}
Le dernier paramètre (le numéro 3) est maintenant facultatif, car nous lui avons donné une valeur par défaut (0). Lorsque vous l'appelez, vous pouvez maintenant fournir deux ou trois valeurs, comme ceci :
public void Main(string[] args)
{
AddNumbers(38, 4);
AddNumbers(36, 4, 2);
}
Vous pouvez rendre plus d'un paramètre facultatif - en fait, votre méthode peut être composée uniquement de paramètres facultatifs si nécessaire. Rappelez-vous simplement que les paramètres optionnels doivent figurer en dernier dans la déclaration de la méthode - et non en premier ou entre des paramètres non optionnels.
Les Modificateurs de Paramètres
Au lieu d'un certain nombre de paramètres facultatifs, vous pouvez utiliser le modificateur de paramètres pour autoriser un nombre arbitraire de paramètres. Cela pourrait ressembler à ceci :
public void GreetPersons(params string[] names) { }
L'appel pourrait alors ressembler à ceci :
GreetPersons("John", "Jane", "Tarzan");
Un autre avantage de l'utilisation de l'approche paramètres est que vous êtes également autorisé à passer zéro paramètre à la méthode. Les méthodes avec params peuvent également prendre des paramètres ordinaires, à condition que le paramètre avec le modificateur params soit le dernier. En outre, un seul paramètre utilisant le mot clé params peut être utilisé par méthode. Voici un exemple complet où nous utilons le modificateur params pour imprimer un nombre variable de noms avec notre méthode GreetPersons :
public void Main(string[] args)
{
GreetPersons("John", "Jane", "Tarzan");
}
public void GreetPersons(params string[] names)
{
foreach(string name in names)
Console.WriteLine("Hello " + name);
}
Types de paramètres : valeur ou référence
C#, ainsi que d'autres langages de programmation, distingue deux types de paramètres : "par valeur" et "par référence". Par défaut en C# c'est "par valeur", ce qui signifie que lorsque vous passez une variable à un appel de méthode, vous envoyez en fait une copie de l'objet, au lieu d'une référence à celui-ci. Cela signifie également que vous pouvez apporter des modifications au paramètre depuis l'intérieur de la méthode, sans affecter l'objet original que vous avec passé en paramètre.
Nous pouvons facilement démontrer ce comportement à l'aide d'un exemple :
public void Main(string[] args)
{
int number = 20;
AddFive(number);
Console.WriteLine(number);
}
public void AddFive(int number)
{
number = number + 5;
}
Nous avons une méthode très basique appelée AddFive() qui ajoute 5 au nombre que nous lui passons. Ainsi, dans notre méthode Main(), nous créons une variable appelée number avec la valeur 20, puis nous appelons la méthode AddFive(). Maintenant, à la ligne suivante, lorsque nous écrivons la variable number, on pourrait s'attendre à ce que la valeur soit maintenant 25, mais au lieu de cela, elle reste à 20. Pourquoi ? Parce que par défaut, le paramètre a été transmis comme une copie de l'objet original (par valeur), donc lorsque notre méthode AddFive() a travaillé sur le paramètre, elle a travaillé sur une copie et n'a donc jamais affecté la variable originale.
Il existe actuellement deux façons de modifier ce comportement, afin que notre méthode AddFive() soit autorisée à modifier la valeur d'origine : Nous pouvons utiliser le modificateur ref ou les modificateurs in/out.
The ref modifier
Le modificateur ref est un raccourci pour "référence" et il modifie essentiellement le comportement du paramètre par défaut "par valeur" en "par référence", ce qui signifie que nous passons maintenant une référence à la variable d'origine au lieu d'une copie de sa valeur. Voici un exemple modifié :
public void Main(string[] args)
{
int number = 20;
AddFive(ref number);
Console.WriteLine(number);
}
public void AddFive(ref int number)
{
number = number + 5;
}
Vous remarquerez que j'ai ajouté le mot-clé "ref" à deux endroits : dans la déclaration de la méthode et lors du passage du paramètre dans l'appel de la méthode. Avec cette modification, nous obtenons maintenant le comportement que nous attendions initialement - le résultat est maintenant 25 au lieu de 20, car le modificateur ref permet à la méthode de travailler sur la valeur réelle passée en paramètre au lieu d'une copie.
Le modificateur out (de sortie)
Tout comme le modificateur ref, le modificateur out garantit que le paramètre est passé par référence plutôt que par valeur, mais il y a une différence majeure: lorsque vous utilisez le modificateur ref, vous passez une valeur initialisée que vous pouvez choisir de modifier à l'intérieur de la méthode, ou la laisser telle quelle. D'autre part, lorsque vous utilisez le modificateur out, vous êtes obligé d'initialiser le paramètre à l'intérieur de la méthode. Cela signifie également que vous pouvez passer des valeurs non initialisées lorsque vous utilisez le modificateur out - le compilateur se plaindra si vous essayez de quitter une méthode avec un paramètre out sans lui assigner une valeur.
En C#, une méthode ne peut retourner qu'une seule valeur, mais si vous utilisez le modificateur out, vous pouvez contourner cela en passant plusieurs paramètres avec le modificateur out - lorsque la méthode a été appelée, tous les paramètres out auront été assignés. Voici un exemple, où nous passons deux nombres et, en utilisant des modificateurs out, retournons à la fois une addition et une soustraction en utilisant ces nombres :
public void Main(string[] args)
{
int addedValue, subtractedValue;
DoMath(10, 5, out addedValue, out subtractedValue);
Console.WriteLine(addedValue);
Console.WriteLine(subtractedValue);
}
public void DoMath(int number1, int number2, out int addedValue, out int subtractedValue)
{
addedValue = number1 + number2;
subtractedValue = number1 - number2;
}
Output:
15
5
Comme vous pouvez le voir au début de l'exemple, j'ai déclaré les deux variables (addedValue et subtractedValue) avant de les passer en tant que paramètres out. C'était une exigence dans les versions précédentes du langage C#, mais à partir de la version C# 6, vous pouvez les déclarer directement dans l'appel de la méthode, comme ceci :
DoMath(10, 5, out int addedValue, out int subtractedValue);
Console.WriteLine(addedValue);
Console.WriteLine(subtractedValue);
Le modificateur In
Tout comme le modificateur out, le modificateur in garantit que le paramètre est passé en tant que référence plutôt qu'une copie de la valeur, mais contrairement au modificateur out, le modificateur in empêchera toute modification de la variable à l'intérieur de la méthode.
Votre première idée pourrait être : si ne peux pas changer la valeur du paramètre, autant le passer en tant que paramètre régulier, où les modifications n'affecteront pas la variable d'origine. Et vous avez raison, le résultat semblerait exactement le même, mais il y a toujours une raison très valable d'utiliser le modificateur in: en le passant en tant que référence plutôt qu'en valeur, vous économisez des ressources car le framework n'a pas à passer du temps à créer une copie de l'objet lors de son passage à la méthode comme un paramètre régulier.
Dans la plupart des cas, cela n'aura pas beaucoup d'importance, car la plupart des paramètres sont des chaînes ou des entiers simples, mais dans des situations où vous appelez plusieurs fois la même méthode dans une boucle ou vous passez des paramètres avec des valeurs conséquentes, par exemple des chaînes ou des structures très volumineuses, cela peut vous donner un joli coup de pouce en termes de performances.
Voici un exemple où nous utilisons le modificateur in :
public void Main(string[] args)
{
string aVeryLargeString = "Lots of text...";
InMethod(aVeryLargeString);
}
public void InMethod(in string largeString)
{
Console.WriteLine(largeString);
}
In our method, InMethod(), the largeString parameter is now a read-only reference to the original variable (aVeryLargeString), so we're able to use it, but not modify it. If we try, the compiler will complain:
public void InMethod(in string largeString)
{
largeString = "We can't do this...";
}
Error: Cannot assign to variable 'in string' because it is a readonly variable
Paramètres nommés
Comme vous avez pu le voir dans les exemples précédents, chaque paramètre a un nom unique dans la déclaration de méthode. Ceci vous autorise à référencer le paramètre à l’intérieur de la méthode. Cependant lorsque vous appelez la méthode, vous n'utilisez pas ces noms, vous devez stocker les valeurs dans le même ordre que vous les avez déclarées. Ce n'est pas un problème pour des méthodes simples prenant 2 ou 3 paramètres mais certaine méthodes sont plus complexes et requiert plus de paramètre. Dans ces situations il peut être difficile de se rendre compte des valeurs variées dans un appel de méthodes faisant référence, comme dans cet exemple :
PrintUserDetails(1, "John", 42, null);
Dans cet appel de méthode, les paramètres ne sont pas vraiment clairs mais si vous regarder la déclaration de la méthode , vous pouvez le voir :
public void PrintUserDetails(int userId, string name, int age = -1, List<string> addressLines = null)
{
// Print details...
}
But it's annoying if you constantly have to look up the method declaration to understand what the parameters are doing, so for more complex methods, you can supply the parameter names directly in the method call. This also allows you to supply the parameter names in any order, instead of being forced to use the declaration order. Here's an example:
PrintUserDetails(name: "John Doe", userId: 1);
As an added bonus, this will allow you to supply a value for any of your optional parameters, without having to supply values for all previous optional parameters in the declaration. In other words, if you want to supply a value for the addressLines parameter in this example you would also have to provide a value for the age parameter, because it comes first in the method declaration. However, if you use named parameters, order no longer matters and you can just supply values for the required parameters as well as one or several of the optional parameters, e.g. like this:
PrintUserDetails(addressLines: new List<string>() { }, name: "Jane Doe", userId: 2);
Here's the complete example of using named parameters:
public void Main(string[] args)
{
PrintUserDetails(1, "John", 42, null);
PrintUserDetails(name: "John Doe", userId: 1);
PrintUserDetails(addressLines: new List<string>() { }, name: "Jane Doe", userId: 2);
}
public void PrintUserDetails(int userId, string name, int age = -1, List<string> addressLines = null)
{
// Print details...
Console.WriteLine(name + " is " + age + " years old...");
}
Summary
As you can see from this article, parameters come in many forms and types. Fortunately, you'll come along way with plain, old regular parameters, but once you start to dig deeper into the C# language, you will benefit from knowing all the types and modifiers as explained in this article.