Type valeur et type référence en C#

Une variable, au niveau physique, est un emplacement mémoire, repéré par une adresse binaire. Au niveau abstrait, c’est une association entre un nom et une zone mémoire. La taille de cette dernière et l’interprétation de son contenu dépendent du type de la variable.
Le langage de programmation C# compte 2 types de variable :

  • Les variables de type valeur stockent des données
  • Les variables de type référence stockent les références aux données

Il est important de connaître les caractéristiques des deux types et leur impact sur la mémoire afin de concevoir une application performante.

Les informations relatives à un type peuvent inclure les éléments suivants :

  • Espace de stockage que nécessite une instance du type.
  • Valeurs minimale et maximale du type.
  • Membres (méthodes, champs, événements,…) du type.
  • Opérations autorisées par le type.
  • Type de base dont hérite le type.
  • Emplacement où sera allouée la mémoire pour une instance du type.

Lors de la déclaration d’une variable ou d’une constante, il faut spécifier son type ou utiliser le mot clé var pour permettre au compilateur de déduire le type.

float température;
string _nom;
Program maClasse;

char uneLettre = 'C';
var limite = 3;
int[] source = { 0, 1, 2, 3, 4, 5 };
var requête = from élément in source
              where élément = limite
              select élément;
  • Le type valeur

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 classe string, qui est un type référence.

Les variables de type valeur contiennent directement leurs valeurs. Cela signifie que lorsque cette variable est modifiée, la valeur qu’elle contenait est aussi modifiée. Elles dérivent toutes de ValueType, qui lui dérive de la classe Object.

Les types valeur sont sealed (donc non dérivables). Ce qui implique, par exemple, qu’il n’est pas possible de dériver un type de Int32. Ni de définir un struct pour qu’il hérite d’une classe ou d’un struct défini par l’utilisateur car un struct peut uniquement hériter de ValueType.

Les types valeur sont également Nullable, ce qui signifie qu’ils peuvent stocker un état de non-valeur.

Il existe deux catégories de types valeur : struct et enum.

  1. Les structures (struct) sont utilisées généralement comme conteneurs pour un petit jeu de variables connexes et elles sont réparties dans les catégories suivantes :
  •  Types numériques
    • Types intégraux
    • Types virgule flottante
    • Decimal
  • bool
  • Structures définies par l’utilisateur.
public struct CoOrds
{
    public int x, y;
    public CoOrds(int p1, int p2)
    {
        x = p1;
        y = p2;
    }
}
  1. Une énumération (enum) définit un jeu de constantes intégrales nommées. Toutes les règles qui s’appliquant à un struct s’appliquent également à un enum.
    Exemple : l’énumération FileMode contient un jeu d’entiers constants nommés qui indiquent comment un fichier doit être ouvert.
public enum FileMode
{    
    CreateNew = 1,    
    Create = 2,    
    Open = 3,    
    OpenOrCreate = 4,    
    Truncate = 5,    
    Append = 6,
}
  • Type référence

C# fournit les types référence intégrés suivants : dynamic, object, String
Les types classe, délégué, tableau ou interface sont des types référence.
Une référence à (adresse de) l’emplacement mémoire de l’objet est affectée à la variable lors qu’une instance de l’objet est crée à l’aide de l’opérateur new ou qu’un objet créé ailleurs à l’aide de new lui est assigné.

// Instanciation d’une classe à l’aide du mot clé new. 
UneClasse mc = new UneClasse();
// Assignation d’un objet précédement créé à un objet de type référence 
UneClasse mc2 = mc;

// Déclarer un tableau d’entiers. 
int[] numero = { 1, 2, 3, 4, 5 };
// Accès à la propriété d’une instance de System.Array. 
int longueur = numero.Length;

Les types référence prennent complètement en charge l’héritage. Une classe peut hériter de toute autre interface ou classe qui n’est pas définie comme sealed.

Avec les types référence, deux variables peuvent faire référence au même objet ; par conséquent, les opérations sur une variable peuvent affecter le même objet référencé par l’autre variable.

Il est également possible d’utiliser les alias définis au niveau de Visual C#.
Exemple : Le type System.Int32 défini au niveau du framework peut être remplacé par le type int dans Visual C#.

La valeur d’une variable de type référence est toujours soit une référence, soit null. Si c’est une référence, ce doit être une référence à un objet qui est compatible avec le type de la variable.
Exemple : une variable déclarée en tant que Stream aura toujours soit la valeur null soit une référence à une instance de la classe Stream ou une sous-classe de Stream.

La zone de mémoire associée à la variable est juste la taille d’une référence, quelle que soit la taille de l’objet (information réelle) auquel elle pointe.
Exemple : sur le Framework .Net (32bits), la taille d’une variable de type référence est quatre octets.

Il est possible de convertir un type valeur en type référence en effectuant le boxing, puis de revenir en type valeur, en effectuant le unboxing.

  • Emplacement de mémoire

Selon le contexte de déclaration d’une variable, la zone mémoire est stockée soit sur la pile soit sur le tas.

  • Une variable de type référence est toujours sur le tas. La mémoire sera libérée que lorsque le système de garbage collection de C# aura déterminé qu’elle n’est plus nécessaire. Les types référence sont plus gourmands en mémoire mais ont l’avantage d’être accessibles depuis d’autres classes.

 

  • Une variable statique (de type référence ou valeur) est stockée sur le tas.

 

  • Une variable statique (de type référence ou valeur) est stockée sur le tas.

 

  • Une variable locale est stockée dans la pile. Les paramètres de méthodes aussi, sauf si elles sont déclarées avec le modificateur ref, elles ne reçoivent pas leur propre zone mémoire, mais partagent une zone mémoire avec les variables utilisées dans le code appelant.

 

  • L’espace mémoire réservé à une variable de type valeur est allouée La variable est stockée dans le même contexte où est déclaré le type. En d’autres termes, une variable struct déclarée dans une méthode est stockée sur la pile, alors qu’une variable struct qui est un champ d’instance d’une classe est stockée sur le tas.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *