Partager via


Types de structure ref (Informations de référence sur C#)

Vous pouvez utiliser le modificateur ref dans la déclaration d’un type de structure. Les instances d’un type ref struct sont allouées sur la pile et ne peuvent pas passer au tas managé. Pour le garantir, le compilateur limite l’utilisation des types ref struct comme suit :

  • Un ref struct ne peut pas être le type d’élément d’un tableau.
  • Un ref struct ne peut pas être un type déclaré d’un champ d’une classe ou un type autre que ref struct.
  • Un ref struct ne peut pas être converti (boxed) en System.ValueType ou System.Object.
  • Une variable ref struct ne peut pas être capturée dans une expression lambda ou une fonction locale.
  • Avant C# 13, vous ne pouviez par utiliser de variables ref struct dans une méthode async. À compter de C# 13, vous ne pouvez par utiliser de variable ref struct dans le même bloc que l’expression await dans une méthode async. Toutefois, vous pouvez utiliser des variables ref struct dans des méthodes synchrones, par exemple, dans les méthodes qui retournent Task ou Task<TResult>.
  • Avant C# 13, vous ne pouviez par utiliser de variables ref struct dans des itérateurs. À partir de C# 13, vous pouvez utiliser les types ref struct et les variables locales ref dans des itérateurs, à condition qu’ils ne se trouvent pas dans des segments de code avec l’instruction yield return.
  • Avant C# 13, un ref struct ne pouvait pas implémenter d’interfaces. À compter de C# 13, un struct ref peut implémenter des interfaces, mais il doit adhérer aux règles de sécurité de référence. Par exemple, un type ref struct ne peut pas être converti en type d’interface, car l’opération nécessite une conversion boxing.
  • Avant C# 13, un ref struct ne pouvait pas être un argument de type. À compter de C# 13, un ref struct peut être un argument de type quand le paramètre de type spécifie le allows ref struct dans sa clause where.

En règle générale, vous définissez un type ref struct lorsque vous avez besoin d’un type incluant aussi des membres de données des types ref struct :

public ref struct CustomRef
{
    public bool IsValid;
    public Span<int> Inputs;
    public Span<int> Outputs;
}

Pour déclarer un ref struct en readonly, combinez les modificateurs readonly et ref dans la déclaration de type (le modificateur readonly doit être placé avant le modificateurref) :

public readonly ref struct ConversionRequest
{
    public ConversionRequest(double rate, ReadOnlySpan<double> values)
    {
        Rate = rate;
        Values = values;
    }

    public double Rate { get; }
    public ReadOnlySpan<double> Values { get; }
}

Dans .NET, System.Span<T> et System.ReadOnlySpan<T> sont des exemples de ref struct.

Champs ref

À compter de C# 11, vous pouvez déclarer un champ ref dans un ref struct, comme le montre l’exemple suivant :

public ref struct RefFieldExample
{
    private ref int number;

    public int GetNumber()
    {
        if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
        {
            throw new InvalidOperationException("The number ref field is not initialized.");
        }

        return number;
    }
}

Un champ ref peut avoir la valeur null. Utilisez la méthode Unsafe.IsNullRef<T>(T) pour déterminer si un champ ref a la valeur null.

Vous pouvez appliquer le modificateur readonly à un champ ref des manières suivantes :

  • readonly ref : vous pouvez réaffecter le ref d’un tel champ avec l’opérateur = ref uniquement à l’intérieur d’un constructeur ou d’un accesseurinit. Vous pouvez affecter une valeur avec l’opérateur = à n’importe quel moment autorisé par le modificateur d’accès du champ.
  • ref readonly : vous ne pouvez à aucun moment affecter une valeur avec l’opérateur = à un tel champ. En revanche, vous pouvez réaffecter le ref d’un champ avec l’opérateur = ref.
  • readonly ref readonly : vous pouvez uniquement réaffecter le ref d’un tel champ dans un constructeur ou dans un accesseur init. Vous ne pouvez à aucun moment affecter une valeur au champ.

Le compilateur garantit qu’une référence stockée dans un champ ref ne survit pas à son référent.

La fonctionnalité de champs ref permet une implémentation sécurisée de types tels que System.Span<T> :

public readonly ref struct Span<T>
{
    internal readonly ref T _reference;
    private readonly int _length;

    // Omitted for brevity...
}

Le type Span<T> stocke une référence par le biais de laquelle il accède aux éléments contigus en mémoire. Le recours à une référence permet à une instance Span<T> d’éviter de copier le stockage auquel elle fait référence.

Modèle supprimable

Vous pouvez définir un ref struct supprimable. Pour ce faire, assurez-vous qu’un ref struct est conforme au modèle supprimable. Autrement dit, il doit avoir une méthode Dispose d’instance qui soit accessible et sans paramètre, avec un type de retour void. Vous pouvez utiliser l’instruction ou la déclaration using avec une instance d’un ref struct supprimable.

À compter de C# 13, vous pouvez également implémenter le IDisposable sur des types ref struct. Toutefois, la résolution de surcharge préfère le modèle supprimable à la méthode de l’interface. Le compilateur se résout en méthode IDisposable.Dispose uniquement quand une méthode Dispose appropriée est introuvable.

Restrictions pour les types ref struct implémentant une interface

Ces restrictions veillent à ce qu’un type ref struct implémentant une interface obéisse aux règles de sécurité de référence.

  • Un ref struct ne peut pas être converti en instance d’une interface qu’il implémente. Cette restriction inclut la conversion implicite lorsque vous utilisez un type ref struct comme argument lorsque le paramètre est un type d’interface. La conversion entraîne une conversion boxing qui viole la sécurité de référence.
  • Un ref struct qui implémente une interface doit implémenter tous les membres de l’interface. Le ref struct doit implémenter des membres dans lesquels l’interface inclut une implémentation par défaut.

Le compilateur applique ces restrictions. Si vous écrivez des types ref struct implémentant des interfaces, il est possible que chaque nouvelle mise à jour inclue de nouveaux membres d’interface par défaut. Votre application ne compilera que lorsque vous aurez fourni une implémentation pour ces nouvelles méthodes.

Important

Un ref struct implémentant une interface inclut le risque de changements cassants binaires et de changements cassants de source ultérieurs. L’arrêt se produit si un ref struct implémente une interface définie dans un autre assembly et que celui-ci fournit une mise à jour qui ajoute des membres par défaut à cette interface.

L’arrêt source se produit quand vous recompilez le ref struct : il doit implémenter le nouveau membre même s’il existe une implémentation par défaut.

L’arrêt binaire se produit si vous mettez à niveau l’assembly externe sans recompiler le ref struct type et si le code mis à jour appelle l’implémentation par défaut de la nouvelle méthode. Le runtime lève une exception quand le membre par défaut est accessible.

spécification du langage C#

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

Pour plus d’informations sur les champs ref, consultez la note de proposition Améliorations des structs de bas niveau.

Voir aussi