Tipi struttura ref (Riferimenti per C#)

È possibile usare il modificatore ref nella dichiarazione di un tipo struttura. Le istanze di un tipo ref struct vengono allocate nello stack e non è possibile eseguirne l'escape nell'heap gestito. Per garantire ciò, il compilatore limita l'utilizzo dei tipi ref struct come indicato di seguito:

  • Un tipo ref struct non può essere il tipo di elemento di una matrice.
  • Un tipo ref struct non può essere un tipo dichiarato di un campo di una classe o di un tipo non ref struct.
  • Un tipo ref struct non può implementare interfacce.
  • Un tipo ref struct non può essere sottoposto a conversione boxing in System.ValueType o System.Object.
  • Un tipo ref struct non può essere un argomento tipo.
  • Una variabile di tipo ref struct non può essere acquisita da un'espressione lambda o da una funzione locale.
  • Una variabile di tipo ref struct non può essere usata in un metodo async. Tuttavia, è possibile usare le variabili ref struct nei metodi sincroni, ad esempio nei metodi che restituiscono Task o Task<TResult>.
  • Una variabile di tipo ref struct non può essere usata negli iteratori.

È possibile definire un tipo ref struct eliminabile. A tale scopo, assicurarsi che un tipo ref struct corrisponda al criterio eliminabile. Ovvero, abbia un metodo di istanza Dispose, sia accessibile, senza parametri e abbia un tipo restituito void. È possibile usare l'istruzione o la dichiarazione using con un'istanza di un tipo ref struct eliminabile.

In genere, un tipo ref struct viene definito quando è necessario un tipo che includa anche membri dati di tipi ref struct:

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

Per dichiarare un tipo ref struct come readonly, combinare i modificatori readonly e ref nella dichiarazione di tipo (il modificatore readonly deve precedere il modificatore ref):

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; }
}

In .NET gli esempi di un tipo ref struct sono System.Span<T> e System.ReadOnlySpan<T>.

Campi ref

A partire da C# 11, è possibile dichiarare un campo ref in un tipo ref struct, come illustrato nell'esempio seguente:

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 campo ref può avere il valore null. Usare il metodo Unsafe.IsNullRef<T>(T) per determinare se un campo ref è null.

È possibile applicare il modificatore readonly a un campo ref nei modi seguenti:

  • readonly ref: è possibile riassegnare un valore ref a un campo di questo tipo con l'operatore = ref solo all'interno di un costruttore o di una funzione di accesso init. È possibile assegnare un valore con l'operatore = in qualsiasi punto consentito dal modificatore di accesso al campo.
  • ref readonly: non è possibile assegnare un valore con l'operatore = a tale campo in qualsiasi momento. Tuttavia, è possibile riassegnare un valore ref a un campo con l'operatore = ref.
  • readonly ref readonly: è possibile riassegnare un valore ref a un campo di questo tipo solo in un costruttore o in una funzione di accesso init. Non è possibile assegnare un valore al campo in qualsiasi momento.

Il compilatore garantisce che un riferimento archiviato in un campo ref non sopravviva al suo referente.

La funzionalità dei campi ref consente un'implementazione sicura dei tipi come System.Span<T>:

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

    // Omitted for brevity...
}

Il tipo Span<T> archivia un riferimento tramite il quale accede agli elementi contigui in memoria. L'uso di un riferimento consente a un'istanza Span<T> di evitare di copiare lo spazio di archiviazione a cui fa riferimento.

Specifiche del linguaggio C#

Per altre informazioni, vedere le sezioni seguenti delle specifiche del linguaggio C#:

Per altre informazioni sui campi ref, vedere la nota nella proposta Miglioramenti dello struct di basso livello.

Vedi anche