Freigeben über


ref-Strukturtypen (C#-Referenz)

Verwenden Sie den ref Modifizierer beim Deklarieren eines Strukturtyps. Sie weisen Instanzen eines ref struct Typs im Stapel zu, und sie können dem verwalteten Heap nicht escapeen. Um diese Eigenschaft sicherzustellen, beschränkt der Compiler die Verwendung von ref struct Typen wie folgt:

  • Sie können einen ref struct Elementtyp eines Arrays nicht verwenden.
  • Sie können einen ref struct Feldtyp in einer Klasse oder nichtref struct als Typ deklarieren.
  • Sie können kein Feld für ref structSystem.ValueType oder System.Object.
  • Sie können keine ref struct Variable in einem Lambda-Ausdruck oder einer lokalen Funktion erfassen.
  • Vor C# 13 können Sie keine Variablen in einer async Methode verwendenref struct. Ab C# 13 kann eine ref struct-Variable nicht im selben Block wie der await-Ausdruck in einer async-Methode verwendet werden. Sie können ref struct-Variablen jedoch in synchronen Methoden verwenden, z. B. in solchen, die Task oder Task<TResult> zurückgeben.
  • Vor C# 13 können Sie keine Variable in Iteratoren verwendenref struct. Ab C# 13 können ref struct-Typen und lokale ref-Variablen in Iteratoren verwendet werden, vorausgesetzt, sie befinden sich nicht in Codesegmenten mit der yield return-Anweisung.
  • Vor C# 13 kann eine ref struct keine Schnittstellen implementieren. Ab C# 13 kann eine ref-Struktur Schnittstellen implementieren, muss jedoch den Regeln für die Verweissicherheit folgen. Beispielsweise kann ein ref struct-Typ nicht in den Schnittstellentyp konvertiert werden, da dies eine Boxing-Konvertierung erfordert.
  • Vor C# 13 kann eine ref struct kein Typargument sein. Ab C# 13 kann eine ref struct das Typargument sein, wenn der Typparameter die allows ref struct in der where-Klausel angibt.

Die C#-Sprachreferenz dokumentiert die zuletzt veröffentlichte Version der C#-Sprache. Außerdem enthält sie erste Dokumentation für Features in der öffentlichen Vorschau für die kommende Sprachversion.

In der Dokumentation werden alle Features identifiziert, die in den letzten drei Versionen der Sprache oder in der aktuellen öffentlichen Vorschau eingeführt wurden.

Tipp

Informationen dazu, wann ein Feature erstmals in C# eingeführt wurde, finden Sie im Artikel zum Versionsverlauf der C#-Sprache.

In der Regel definieren Sie einen ref struct-Typ, wenn Sie einen Typ benötigen, der außerdem Datenmember von ref struct-Typen enthält:

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

Kombinieren Sie die ref struct- und readonly-Modifizierer in der Typdeklaration (der readonly-Modifizierer muss vor dem ref-Modifizierer stehen), um eine readonly als ref zu deklarieren:

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 sind ref struct und System.Span<T> Beispiele für eine System.ReadOnlySpan<T>.

ref-Felder

Sie können ein Feld in einem refref struct, wie das folgende Beispiel zeigt, deklarieren:

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

Ein ref-Feld kann den Wert null aufweisen. Verwenden Sie die Unsafe.IsNullRef<T>(T)-Methode, um zu bestimmen, ob ein ref-Feld null ist.

Sie können den readonly-Modifizierer wie folgt auf ein ref-Feld anwenden:

  • readonly ref: Sie können dieses Feld erneut zuweisen , indem Sie den = ref Operator nur innerhalb eines Konstruktors oder eines init Accessors verwenden. Sie können mit dem =-Operator an jedem beliebigen Punkt einen Wert zuweisen, der durch den Feldzugriffsmodifizierer zugelassen wird.
  • ref readonly: An jedem Punkt können Sie diesem Feld keinen Wert mit dem = Operator zuweisen. Sie können das Feld jedoch mithilfe des = ref Operators neu zuweisen.
  • readonly ref readonly: Sie können dieses Feld nur in einem Konstruktor oder einem init Accessor neu zuweisen. An keinem Punkt können Sie dem Feld einen Wert zuweisen.

Der Compiler stellt sicher, dass ein in einem ref-Feld gespeicherter Verweis nicht länger vorhanden ist als das Element, auf das er verweist.

Das Feldfeature ref ermöglicht eine sichere Implementierung von Typen wie System.Span<T>:

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

    // Omitted for brevity...
}

Der Span<T>-Typ speichert einen Verweis, über den er auf die zusammenhängenden Elemente im Arbeitsspeicher zugreift. Durch Die Verwendung eines Verweises verhindert eine Span<T> Instanz das Kopieren des speichers, auf den sie verweist.

Das verwerfbare Muster

Sie können eine verwerfbare ref structdefinieren. Stellen Sie dazu sicher, dass eine ref struct dem Dispose-Muster entspricht. Das heißt, es verfügt über eine Instanzmethode Dispose , die barrierefrei, parameterlos ist und einen void Rückgabetyp aufweist. Sie können die using-Anweisung oder -Deklaration mit einer Instanz einer verwerfbaren ref struct verwenden.

Ab C# 13 können Sie die IDisposable auch für ref struct-Typen implementieren. Die Überladungsauflösung bevorzugt jedoch das verwerfbare Muster gegenüber der Schnittstellenmethode. Der Compiler wird nur dann in eine IDisposable.Dispose Methode aufgelöst, wenn eine geeignete Dispose Methode nicht gefunden wird.

Einschränkungen für ref struct-Typen, die eine Schnittstelle implementieren

Diese Einschränkungen stellen sicher, dass ein ref struct Typ, der eine Schnittstelle implementiert, den erforderlichen Refsicherheitsregeln folgt.

  • Sie können eine ref struct Instanz einer von ihr implementierten Schnittstelle nicht in eine Instanz konvertieren. Diese Einschränkung enthält die implizite Konvertierung, wenn Sie einen ref struct Typ als Argument verwenden und der Parameter ein Schnittstellentyp ist. Die Konvertierung führt zu einer Boxing-Konvertierung, die gegen die Verweissicherheit verstößt. Ein ref struct kann Methoden als explizite Schnittstellendeklarationen deklarieren. Sie können jedoch nur über generische Methoden, bei denen die Typparametertypen allows ref struct verwendet werden, auf diese Methoden zugreifen.
  • Eine ref struct, die eine Schnittstelle implementiert, muss alle Instanz-Schnittstellenmember implementieren. Die ref struct muss Instanzmember implementieren, auch wenn die Schnittstelle eine Standardimplementierung enthält.

Der Compiler erzwingt diese Einschränkungen. Wenn Sie ref struct-Typen schreiben, die Schnittstellen implementieren, enthält jedes neue Update möglicherweise neue Standardschnittstellenmitglieder. Bis Sie eine Implementierung für neue Instanzmethoden bereitstellen, wird ihre Anwendung nicht kompiliert. Sie können keine bestimmte Implementierung für eine static Schnittstellenmethode mit einer Standardimplementierung bereitstellen.

Wichtig

Durch die Implementierung einer Schnittstelle mit einem ref struct Typ wird das Potenzial für spätere Änderungen beim Quellbruch und binären Unterbrechungen eingeführt. Der Umbruch tritt auf, wenn eine in einer ref struct anderen Assembly definierte Schnittstelle implementiert und diese Assembly ein Update bereitstellt, das dieser Schnittstelle Standardmember hinzufügt.

Der Quellumbruch erfolgt, wenn Sie das ref structelement neu kompilieren: Er muss das neue Element implementieren, obwohl es eine Standardimplementierung gibt.

Der binäre Umbruch erfolgt, wenn Sie die externe Assembly aktualisieren, ohne den ref struct Typ neu zu kompilieren , und der aktualisierte Code ruft die Standardimplementierung der neuen Methode auf. Die Runtime löst eine Ausnahme aus, wenn auf das Standardmitglied zugegriffen wird.

C#-Sprachspezifikation

Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:

Weitere Informationen zu ref-Feldern finden Sie im Vorschlag zu Strukturverbesserungen auf niedriger Ebene.

Weitere Informationen