• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 10/03/2017

Comment fonctionne le passage des paramètres à une méthode ?

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans le cours précédent, nous avons décrit comment on pouvait passer des paramètres à une méthode. Nous avons également vu que les types du framework .NET pouvaient être des types valeur ou des types référence. Ceci influence la façon dont sont traités les paramètres d'une méthode. Nous allons ici préciser un peu ce fonctionnement.

Dans ce chapitre, je vais illustrer mes propos en utilisant des méthodes statiques écrites dans la classe Program, générée par Visual Studio Express. Le but est de simplifier l'écriture et de ne pas s'encombrer d'objets inutiles. Évidemment, tout ce que nous allons voir fonctionne également de la même façon avec les méthodes non statiques présentes dans des objets.

Passage de paramètres par valeur

Dans le cours précédent, nous avons appelé des méthodes en passant des types simples (int, string, etc.). Nous avons vu qu’il s’agissait de types valeur qui possèdent directement la valeur dans la variable.

Lorsque nous passons des types valeur en paramètre d’une méthode, nous utilisons un passage de paramètre par valeur.

Décortiquons l’exemple suivant :

static void Main(string[] args)
{
    int age = 30;
    Doubler(age);
    Console.WriteLine(age);
}

public static void Doubler(int valeur)
{
    valeur = valeur * 2;
    Console.WriteLine(valeur);
}

Nous déclarons dans la méthode Main() une variable age, de type entier, à laquelle nous affectons la valeur 30.
Nous appelons ensuite la méthode Doubler() en lui passant cette variable en paramètre.

Ce qu’il se passe c’est que le compilateur fait une copie de la valeur de la variable age pour la mettre dans la variable valeur de la méthode Doubler(). La variable valeur a une portée égale au corps de la méthode Doubler().

Nous modifions ensuite la valeur de la variable valeur en la multipliant par deux. Étant donné que la variable valeur a reçu une copie de la variable age, c'est-à-dire que le compilateur a dupliqué la valeur 30, le fait de modifier la variable valeur ne change en rien la valeur de la variable age.

En effet, si nous exécutons le code du dessus, nous allons avoir :

Image utilisateur

Nous passons 30 à la méthode Doubler() qui calcule le double de la variable valeur. On affiche 60. Lorsqu’on revient dans la méthode Main(), nous retrouvons la valeur initiale de la variable age. Elle n’a bien sûr pas été modifiée car la méthode Doubler() a travaillé sur une copie.

Rappelez-vous que ceci est possible car les types intégrés sont facilement copiables, car peu évolués.

Passage de paramètres en mise à jour

Oui mais si je veux modifier la valeur ?

Pour pouvoir modifier la valeur du paramètre passé, il faut indiquer que la variable est en mode « mise à jour ». Cela se fait grâce au mot-clé « ref » que nous pourrons utiliser ainsi :

static void Main(string[] args)
{
    int age = 30;
    Doubler(ref age);
    Console.WriteLine(age);
}

public static void Doubler(ref int valeur)
{
    valeur = valeur * 2;
}

Comme on peut s’en douter, ce code affiche 60.

Le mot-clé ref s’utilise avant la définition du paramètre dans la méthode. Cela implique qu’il soit également utilisé au moment d’appeler la méthode.

Vous aurez remarqué que le mot-clé utilisé est ref et qu'il ressemble beaucoup au mot « référence ». Ce n’est évidemment pas un hasard.
En fait, avec ce mot-clé nous demandons au compilateur de passer en paramètre une référence vers la variable age plutôt que d’en faire une copie. Ainsi, la méthode Doubler() récupère une référence et la variable valeur référence alors la même valeur que la variable age. Ceci implique que toute modification de la valeur référencée provoque un changement sur la variable source puisque les variables référencent la même valeur.

Voilà pourquoi la variable est modifiée après le passage dans la méthode Doubler().
Bien sûr, il aurait tout à fait été possible de faire en sorte que la méthode Doubler() renvoie un entier contenant la valeur passée en paramètre multipliée par 2 :

static void Main(string[] args)
{
    int age = 30;
    age = Doubler(age);
    Console.WriteLine(age);
}

public static int Doubler(int valeur)
{
    return valeur * 2;
}

C’est ce que nous avons toujours fait auparavant. Voici donc une autre façon de faire qui peut être bien utile quand il y a plus d’une valeur à renvoyer.

Passage des objets par référence

C’est aussi comme ça que cela fonctionne pour les objets. Nous avons vu que les variables qui stockent des objets possèdent en fait la référence de l’objet. Le fait de passer un objet à une méthode équivaut à passer la référence de l’objet en paramètres. Ainsi, c’est comme si on utilisait le mot-clé ref implicitement.

Le code suivant :

static void Main(string[] args)
{
    Voiture voiture = new Voiture { Couleur = "Grise" };
    Repeindre(voiture);
    Console.WriteLine(voiture.Couleur);
}

public static void Repeindre(Voiture voiture)
{
    voiture.Couleur = "Bleue";
}

va donc créer un objet Voiture et le passer en paramètres à la méthode Repeindre(). Comme Voiture est un type référence, il n’y a pas de duplication de l’objet et une référence est passée à la méthode.
Lorsque nous modifions la propriété Couleur de la voiture, nous modifions bien le même objet que celui présent dans la méthode Main().

Nous aurons donc :

Image utilisateur

Il est à noter quand même que la variable voiture de la méthode Repeindre est une copie de la variable voiture de la méthode Main() qui contiennent toutes les deux une référence vers l'objet de type Voiture. Cela veut dire que l'on accède bien au même objet, d'où le résultat, mais que les deux variables sont indépendantes.
Si nous modifions directement la variable, avec par exemple :

static void Main(string[] args)
{
    Voiture voiture = new Voiture { Couleur = "Grise" };
    Repeindre(voiture);
    Console.WriteLine(voiture.Couleur);
}

public static void Repeindre(Voiture voiture)
{
    voiture.Couleur = "Bleue";
    voiture = null;
}

Alors, ce code continuera à fonctionner, car la variable voiture de la méthode Main() ne vaut pas null. Le fait de modifier la variable de la méthode Repeindre, qui est une copie, n'affecte en rien la variable de la méthode Main().

Par contre, elle est affectée si nous utilisons le mot-clé ref. Par exemple le code suivant :

static void Main(string[] args)
{
    Voiture voiture = new Voiture { Couleur = "Grise" };
    Repeindre(ref voiture);
    Console.WriteLine(voiture.Couleur);
}

public static void Repeindre(ref Voiture voiture)
{
    voiture.Couleur = "Bleue";
    voiture = null;
}

provoquera une erreur. En effet, cette fois-ci, c'est bien la référence qui est passée à nulle et pas une copie de la variable contenant la référence...

Une subtile différence. :-°

Passage de paramètres en sortie

Enfin, le dernier mode de passage est le passage de paramètres en sortie. Il permet de faire en sorte qu’une méthode force l’initialisation d’une variable et que l’appelant récupère la valeur initialisée.
Nous avons déjà vu ce mode de passage quand nous avons étudié les conversions. Souvenez-vous de ce code :

string chaine = "1234";
int nombre;
if (int.TryParse(chaine, out nombre))
    Console.WriteLine(nombre);
else
    Console.WriteLine("Conversion impossible");

La méthode TryParse permet de tester la conversion d’une chaîne. Elle renvoie vrai ou faux en fonction du résultat de la conversion et met à jour l’entier qui est passé en paramètre en utilisant le mot-clé « out ».
Si la conversion réussit, alors l’entier nombre est initialisé avec la valeur de la conversion, calculée dans la méthode TryParse.
Nous pouvons utiliser ensuite la variable nombre car le mot-clé out garantit que la variable sera initialisée dans la méthode.

En effet, si nous prenons l’exemple suivant :

static void Main(string[] args)
{
    int age = 30;
    int ageDouble;
    Doubler(age, out ageDouble);
}

public static void Doubler(int age, out int resultat)
{
}

Nous aurons une erreur de compilation :

Le paramètre de sortie 'resultat' doit être assigné avant que le contrôle quitte la méthode actuelle

En effet, il faut absolument que la variable resultat qui est marquée en sortie ait une valeur avant de pouvoir sortir de la méthode.
Nous pourrons corriger cet exemple avec :

static void Main(string[] args)
{
    int age = 30;
    int ageDouble;
    Doubler(age, out ageDouble);
}

public static void Doubler(int age, out int resultat)
{
    resultat = age * 2;
}

Après l’appel de la méthode Doubler(), ageDouble vaudra donc 60.

Oui, mais quel intérêt par rapport à un return normal ?

Ici, aucun. Cela est pertinent quand nous souhaitons renvoyer plusieurs valeurs, comme c’est le cas pour la méthode TryParse qui renvoie le résultat de la conversion et si la conversion s’est bien passée.
Bien sûr, si l’on n’aime pas trop le mot-clé out, il est toujours possible de créer un objet contenant deux valeurs que l’on retournera à l’appelant, par exemple :

public class Program
{
    static void Main(string[] args)
    {
        string nombre = "1234";
        Resultat resultat = TryParse(nombre);
        if (resultat.ConversionOk)
            Console.WriteLine(resultat.Valeur);
    }

    public static Resultat TryParse(string chaine)
    {
        Resultat resultat = new Resultat();
        int valeur;
        resultat.ConversionOk = int.TryParse(chaine, out valeur);
        resultat.Valeur = valeur;
        return resultat;
    }

}

public class Resultat
{
    public bool ConversionOk { get; set; }
    public int Valeur { get; set; }
}

Ici, notre méthode TryParse renvoie un objet Resultat qui contient les deux valeurs résultantes de la conversion.

En résumé
  • Le type d'une variable passée en paramètres d'une méthode influence la façon dont elle est traitée.

  • Un passage par valeur effectue une copie de la valeur de la variable et la met dans la variable de la méthode.

  • Un passage par référence effectue une copie de la référence mais continue de pointer sur le même objet.

  • On utilise le mot-clé ref pour passer une variable de type valeur à une méthode afin de la modifier.

Exemple de certificat de réussite
Exemple de certificat de réussite