Types valeur (référence C#)

Les types valeur et les types référence sont les deux principales catégories de types C#. Une variable d’un type valeur contient une instance du type. Cela diffère d’une variable d’un type référence, qui contient une référence à une instance du type. Par défaut, lors de l’affectation, en passant un argument à une méthode et en retournant un résultat de méthode, les valeurs de variable sont copiées. Dans le cas de variables de type valeur, les instances de type correspondantes sont copiées. L’exemple suivant illustre ce comportement :

using System;

public struct MutablePoint
{
    public int X;
    public int Y;

    public MutablePoint(int x, int y) => (X, Y) = (x, y);

    public override string ToString() => $"({X}, {Y})";
}

public class Program
{
    public static void Main()
    {
        var p1 = new MutablePoint(1, 2);
        var p2 = p1;
        p2.Y = 200;
        Console.WriteLine($"{nameof(p1)} after {nameof(p2)} is modified: {p1}");
        Console.WriteLine($"{nameof(p2)}: {p2}");

        MutateAndDisplay(p2);
        Console.WriteLine($"{nameof(p2)} after passing to a method: {p2}");
    }

    private static void MutateAndDisplay(MutablePoint p)
    {
        p.X = 100;
        Console.WriteLine($"Point mutated in a method: {p}");
    }
}
// Expected output:
// p1 after p2 is modified: (1, 2)
// p2: (1, 200)
// Point mutated in a method: (100, 200)
// p2 after passing to a method: (1, 200)

Comme l’illustre l’exemple précédent, les opérations sur une variable de type valeur affectent uniquement cette instance du type valeur, stockée dans la variable.

Si un type valeur contient un membre de données d’un type référence, seule la référence à l’instance du type référence est copiée lorsqu’une instance de type valeur est copiée. La copie et l’instance de type valeur d’origine ont accès à la même instance de type référence. L’exemple suivant illustre ce comportement :

using System;
using System.Collections.Generic;

public struct TaggedInteger
{
    public int Number;
    private List<string> tags;

    public TaggedInteger(int n)
    {
        Number = n;
        tags = new List<string>();
    }

    public void AddTag(string tag) => tags.Add(tag);

    public override string ToString() => $"{Number} [{string.Join(", ", tags)}]";
}

public class Program
{
    public static void Main()
    {
        var n1 = new TaggedInteger(0);
        n1.AddTag("A");
        Console.WriteLine(n1);  // output: 0 [A]

        var n2 = n1;
        n2.Number = 7;
        n2.AddTag("B");

        Console.WriteLine(n1);  // output: 0 [A, B]
        Console.WriteLine(n2);  // output: 7 [A, B]
    }
}

Notes

Pour rendre votre code moins sujet aux erreurs et plus robuste, définissez et utilisez des types valeur immuables. Cet article utilise des types valeur mutables uniquement à des fins de démonstration.

Types de types valeur et contraintes de type

Un type valeur peut être l’un des deux types suivants :

  • un type de structure, qui encapsule les données et les fonctionnalités associées
  • un type d’énumération, qui est défini par un ensemble de constantes nommées et représente un choix ou une combinaison de choix

Un typeT? valeur nullable représente toutes les valeurs de son type T valeur sous-jacente et une valeur null supplémentaire. Vous ne pouvez pas affecter null à une variable d’un type valeur, sauf s’il s’agit d’un type valeur nullable.

Vous pouvez utiliser la struct contrainte pour spécifier qu’un paramètre de type est un type valeur non Nullable. Les types de structure et d’énumération satisfont à la struct contrainte. À compter de C# 7.3, vous pouvez utiliser System.Enum dans une contrainte de classe de base (appelée contrainte d’énumération) pour spécifier qu’un paramètre de type est un type d’énumération.

Types valeur intégrés

C# fournit les types valeur intégrés suivants, également appelés types simples :

Tous les types simples sont des types de structure et diffèrent d’autres types de structure dans le sens où ils autorisent certaines opérations supplémentaires :

  • Vous pouvez utiliser des littéraux pour fournir une valeur d’un type simple. Par exemple, 'A' est un littéral de type char, tandis que 2001 est un littéral de type int.

  • Vous pouvez déclarer des constantes des types simples avec le mot clé const. Il n’est pas possible d’avoir des constantes d’autres types de structure.

  • Les expressions constantes, dont les opérandes sont toutes des constantes des types simples, sont évaluées au moment de la compilation.

À compter de C# 7.0, C# prend en charge les tuples de valeur. Un tuple valeur est un type valeur, mais pas un type simple.

spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Voir aussi