Types valeur et référence (Visual C# Express)

Mise à jour : novembre 2007

Contrairement à certains langages de programmation que vous connaissez peut-être, C# possède deux variétés de types de données : valeur et référence. Il est important de connaître la différence si votre application doit être performante ou si vous souhaitez savoir comment C# gère les données et la mémoire.

Lorsqu'une variable est déclarée à l'aide d'un des types de données intégrées de base ou d'une structure définie par l'utilisateur, il s'agit d'un type valeur. Une exception est constituée par le type de données string, qui est un type référence.

Un type valeur stocke son contenu dans la mémoire allouée sur la pile. Par exemple, dans ce cas la valeur 42 est stockée dans une zone de mémoire appelée la pile.

int x = 42;

Lorsque la variable x sort de la portée parce que la méthode dans laquelle elle a été définie a terminé son exécution, la valeur est rejetée de la pile.

Utiliser la pile est efficace, mais la durée de vie limitée des types valeur les rend moins bien adaptés au partage de données entre différentes classes.

Par opposition, un type référence, comme une instance de classe ou de tableau, est alloué dans une zone de mémoire différente appelée tas. Dans l'exemple ci-dessous, l'espace requis pour les dix entiers qui composent le tableau est alloué sur le tas.

int[] numbers = new int[10];

Cette mémoire n'est pas retournée au tas à l'issue de la méthode. Elle ne sera libérée que lorsque le système de garbage collection de C# aura déterminé qu'elle n'est plus nécessaire. La déclaration des types référence implique une charge mémoire supérieure, mais ces types présentent l'avantage d'être accessibles depuis d'autres classes.

Conversions boxing et unboxing

La conversion boxing est le nom donné au processus par lequel un type valeur est converti en type référence. Lorsque vous opérez une conversion boxing sur une variable, vous créez une variable de référence qui pointe vers une nouvelle copie sur le tas. La variable de référence étant un objet, elle peut utiliser toutes les méthodes héritées par chaque objet, comme ToString(). C'est ce qui se passe dans le code suivant :

int i = 67;                              // i is a value type
object o = i;                            // i is boxed
System.Console.WriteLine(i.ToString());  // i is boxed

Vous rencontrerez la conversion unboxing lorsque vous ferez appel à des classes conçues pour être utilisées avec des objets : par exemple, en utilisant ArrayList pour stocker des entiers. Lorsque vous stockez un entier dans ArrayList, celui-ci est soumis à une conversion boxing. Lorsque vous récupérez un entier, il doit être soumis à une conversion unboxing.

System.Collections.ArrayList list = 
    new System.Collections.ArrayList();  // list is a reference type
int n = 67;                              // n is a value type
list.Add(n);                             // n is boxed
n = (int)list[0];                        // list[0] is unboxed

Problèmes de performances

Examinons cela d'un peu plus près. Lorsque les données sont passées dans des méthodes sous forme de paramètres de type valeur, une copie de chaque paramètre est créée sur la pile. Il est clair que si le paramètre en question est un type de données volumineuses, comme une structure définie par l'utilisateur comportant un grand nombre d'éléments, ou si la méthode est exécutée de nombreuses fois, les performances pourront en être affectées.

Dans ces situations, il peut être préférable de passer une référence au type, à l'aide du mot clé ref. Ceci est l'équivalent dans C# de la technique C++ consistant à passer un pointeur à une variable dans une fonction. Comme dans la version C++, cette méthode peut modifier le contenu de la variable, lequel peut ne pas toujours être sûr. Le programmeur doit trouver un compromis entre sécurité et performances.

int AddTen(int number)  // parameter is passed by value
{
    return number + 10;
}
void AddTen(ref int number)  // parameter is passed by reference
{
    number += 10;
}

Le mot clé out est comparable au mot clé ref, mais il indique au compilateur que la méthode doit affecter une valeur au paramètre, sous peine de provoquer une erreur de compilation.

void SetToTen(out int number)
{
    // If this line is not present, the code will not compile.
    number = 10;
}

Voir aussi

Concepts

Initiation au langage C#

Types de données intégrés (Visual C# Express)

Tableaux et collections (Visual C# Express)

Référence

Types valeur (Référence C#)

Types référence (Référence C#)

Conversion boxing et unboxing (Guide de programmation C#)