Une plongée approfondie: les types de valeur et de référence dans .Net

Les types dans Microsoft .Net peuvent être de type valeur ou de type référence. Alors que les types valeur sont généralement stockés dans la pile, les types référence sont stockés dans le tas géré.

Un type valeur dérive de System.ValueType et contient les données dans sa propre allocation de mémoire. En d'autres termes, les variables ou objets ou types de valeurs ont leur propre copie des données.

Un type de référence, quant à lui, étend System.Object et pointe vers un emplacement dans la mémoire qui contient les données réelles. Vous pouvez imaginer un type de référence similaire à un pointeur qui est implicitement déréférencé lorsque vous y accédez. Les types de référence intégrés pris en charge par C # incluent: object, string et dynamic. Tous les types de données fondamentaux, Boolean, Date, structs et enums sont des exemples de types valeur. Exemples de types de référence: chaînes, tableaux, objets de classes, etc. Pour créer des types de référence en C #, vous pouvez tirer parti de ces mots-clés: classe, interface et délégué.

Notez que contrairement à un type référence, vous ne pouvez pas dériver d'un type valeur, ni affecter une valeur nulle directement à un type valeur. Vous pouvez attribuer une valeur Null à un type valeur uniquement en tirant parti des types Nullable - une fonctionnalité ajoutée aux nouvelles versions de .Net Framework. Lorsqu'un type de valeur est copié dans un autre, la valeur est copiée. Par conséquent, vous pouvez manipuler les valeurs qu'elles contiennent indépendamment de l'autre - un changement dans l'un n'affecte pas l'autre. Au contraire, lorsque vous copiez un type de référence dans un autre, la référence est copiée. Si vous modifiez l'un d'entre eux, l'autre est également affecté. Par exemple, si l'une des références est définie sur null, l'autre devient également nulle.

Emplacements de stockage

Le CLR stocke les objets dans trois types d'emplacements de stockage: les registres, la pile ou le tas géré. Alors que les objets de courte durée sont stockés dans des registres ou de la pile, les objets de longue durée sont stockés dans le tas. Comme je l'ai mentionné précédemment, les types de valeur sont généralement stockés dans la pile.

C'est une idée fausse courante selon laquelle les types valeur sont toujours stockés dans la pile. Je dirais plutôt que les types valeur peuvent être stockés dans la pile lorsque la variable est soit une variable temporaire, soit une variable locale et que le compilateur JIT décide de ne pas enregistrer la valeur. En substance, l'emplacement réel d'un type valeur dépend de l'implémentation du compilateur JIT. Notez qu'un type valeur peut être stocké dans un frame de pile, dans le registre CPU ou même dans la mémoire du tas si le type valeur est contenu dans un objet, c'est-à-dire s'il fait partie d'un type référence. Au contraire, les types de référence sont stockés dans le tas GC. La référence est stockée dans une pile tandis que l'objet est alloué dans le tas.

Les instances ou références d'un type valeur sont stockées dans la pile, le registre ou dans le tas selon que la durée de vie de l'instance ou de la référence est de courte ou longue durée. Un type valeur peut résider sur la pile s'il s'agit de variables locales et dans le tas géré s'il s'agit de champs d'une classe, c'est-à-dire qu'ils appartiennent ou font partie d'un type référence.

Passer par valeur et passer par référence

La liste de codes suivante illustre comment vous pouvez passer une variable à une méthode par valeur.

 static void Increment(int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Notez que vous pouvez transmettre un type valeur comme référence à une méthode à l'aide du mot clé ref. La liste de codes suivante illustre cela.

static void Increment(ref int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(ref x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Lorsque le code ci-dessus est exécuté, le message "La valeur de x est: 2" sera affiché dans la console.

Boxe et déballage

La conversion d'un type valeur en type référence est appelée boxing. Le déballage est exactement le contraire - il est défini comme le processus de conversion d'un type de référence en un type de valeur. L'extrait de code suivant illustre la boxe et le déballage en C #.

int i = 100;

Object obj = i; //Boxing

i = (int) obj; //Unboxing