La différence entre les types valeur et les types référence

Description

Cette explication présente l'une des différences majeures qui existe entre les types référence et les types valeur en .Net.

C'est quelque chose à savoir pour veux qui veulent passer les certifs un jour.

Tutoriel

En C#, les pointeurs sont relativement transparents pour le développeur. C'est bien, mais cela signifie que certains concepts sous-jacents sont moins visibles.

Par exemple, en C/C++, pour qu'une méthode modifie la valeur d'une variable "i" de type int, il faut que l'on passe un pointeur vers cette variable. Pourquoi ? Parce que derrière le "i", on a directement sa valeur : 3 par exemple.

Lors de l'appel à la méthode, on copie cette valeur 3. La méthode pourra bien modifier le paramètre qu'on lui aura envoyé, elle ne touchera qu'à une copie de la donnée... et non à l'originale. De ce fait, notre "i" à nous reste bien à 3, même si la méthode s'amuse à remplacer ce 3 par un 9.

Avec l'utilisation des pointeurs, on envoie plus directement 3, mais une référence vers l'emplacement mémoire qui contient ce 3. On créé donc en quelque sorte une nouvelle variable qui contient une adresse vers l'emplacement mémoire qui contient le contenu de "i" (vous suivez ?). Encore une fois, lors de l'appel de la méthode, cette adresse est copiée puis passée à la méthode. Ce qui change, c'est que la méthode va pouvoir, grâce à cette adresse, aller modifier la valeur originale, et non sa copie.

En C#, c'est pareil, mais on en a moins conscience.

Prenons un exemple :

private void AjouteUn(int nb){
    nb++;
    Console.WriteLine("nb vaut : " + nb);
}

Soit l'algo suivant

int i = 3;
Console.WriteLine("i vaut : " + nb);
AjouteUn(i);
Console.WriteLine("i vaut : " + nb);

La sortie de l'algo est la suivante :

i vaut 3
nb vaut 4
i vaut  3 

Pourquoi i vaut-il 3 à la fin du prog ? Parce que la méthode AjouteUn a modifié la copie de la valeur 3 que nous lui avons passée en paramètre, mais elle n'a pas modifiée l'originale. D'où le fait que "i" soit toujours égal à 3, même après l'appel de la méthode.

Si maintenant on a :

private void AjouteUn(ref int nb){
    nb++;
    Console.WriteLine("nb vaut : " + nb);
}
 
int i = 3;
Console.WriteLine("i vaut : " + nb);
AjouteUn(ref i);
Console.WriteLine("i vaut : " + nb);

La sortie est maintenant :

i vaut 3
nb vaut 4
i vaut 4

On a passé une référence (un pointeur) vers notre entier, donc notre méthode peut aller modifier la valeur de i (et non une copie), donc i est donc bien incrémentée de 1 même après la sortie de la méthode.

Venons en maintenant au but de l'article : la différence entre type valeur et type référence.

Derrière le nom d'une variable de type valeur ("i" dans l'exemple), on a directement une donnée concrète. Les types valeur sont les entiers, les singles, les floats, les longs... bref, tous les types "primitifs". Les enum sont aussi des types valeur, puisqu'un élément d'un enum peut se substituer à un entier. On a enfin les "instances" des structs (à ne pas confondre avec les instances de classes).

Par contre, si je déclare un objet complexe nommé "Obj" et de type Form, derrière le litéral obj, j'ai un pointeur (une référence) vers un emplacement mémoire contenant les données associées à mon objet Form. Les instances de classe sont donc des types référence.

2 conclusions importantes :
On doit mettre le mot clé « ref » sur un paramètre d'une méthode s'il s'agit d'un type valeur, et si la méthode doit avoir le pouvoir de modifier cette valeur. Dans tous les autres cas, PAS BESOIN. Si on passe une variable de type référence, la méthode pourra de toutes façons modifier les propriétés de l'objet (on passe une référence, un pointeur).
A chaque fois que l'on appelle une méthode, le Framework .Net copie tous les arguments de l'appelant et donne ces copies à la méthode. Ceci est vrai dans tous les cas, qu'il s'agisse d'entiers (types valeur), d'instances de classe (concrètement une référence vers un emplacement mémoire), ou que sais-je encore.

Ce document intitulé « La différence entre les types valeur et les types référence » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.