ref
-Strukturtypen (C#-Referenz)
Sie können bei der Deklaration eines Strukturtyps den ref
-Modifizierer verwenden. Instanzen eines ref struct
-Typs werden auf dem Stapel zugeordnet und können nicht in den verwalteten Heap überwechseln. Der Compiler grenzt die Nutzung von ref struct
-Typen wie folgt ein, um dies sicherzustellen:
- Eine
ref struct
kann nicht der Elementtyp eines Arrays sein. - Eine
ref struct
kann kein deklarierter Typ eines Felds einer Klasse oder einerref struct
-fremden Struktur sein. - Für eine
ref struct
kann kein Boxing in System.ValueType oder System.Object durchgeführt werden. - Eine
ref struct
-Variable kann nicht in einem Lambdaausdruck oder einer lokalen Funktion erfasst werden. - Vor C# 13
ref struct
können Variablen nicht in einerasync
Methode verwendet werden. Ab C# 13 kann eineref struct
-Variable nicht im selben Block wie derawait
-Ausdruck in einerasync
-Methode verwendet werden. Sie könnenref struct
-Variablen jedoch in synchronen Methoden verwenden, z. B. in solchen, die Task oder Task<TResult> zurückgeben. - Vor C# 13 kann eine
ref struct
-Variable kann nicht in Iteratoren verwendet werden. Ab C# 13 könnenref struct
-Typen und lokaleref
-Variablen in Iteratoren verwendet werden, vorausgesetzt, sie befinden sich nicht in Codesegmenten mit deryield return
-Anweisung. - Vor C# 13 kann eine
ref struct
keine Schnittstellen implementieren. Ab C# 13 kann eineref
-Struktur Schnittstellen implementieren, muss jedoch den Regeln für die Verweissicherheit folgen. Beispielsweise kann einref 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 eineref struct
das Typargument sein, wenn der Typparameter dieallows ref struct
in derwhere
-Klausel angibt.
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 readonly
- und ref
-Modifizierer in der Typdeklaration (der readonly
-Modifizierer muss vor dem ref
-Modifizierer stehen), um eine ref struct
als readonly
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 System.Span<T> und System.ReadOnlySpan<T> Beispiele für eine ref struct
.
ref
-Felder
Ab C# 11 können Sie ein ref
-Feld in einer ref struct
deklarieren, wie im folgenden Beispiel gezeigt:
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 ein solches Feld mit dem= ref
-Operator nur innerhalb eines Konstruktors oder einerinit
-Zugriffsmethodeneu als Verweis zuweisen. Sie können mit dem=
-Operator an jedem beliebigen Punkt einen Wert zuweisen, der durch den Feldzugriffsmodifizierer zugelassen wird.ref readonly
: An keinem Punkt können Sie einem solchen Feld einen Wert mit dem=
-Operator zuweisen. Jedoch können Sie ein Feld mit dem= ref
-Operator als Verweis erneut zuweisen.readonly ref readonly
: Sie können ein solches Feld nur in einem Konstruktor oder einerinit
-Zugriffsmethode als Verweis erneut 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 muss eine Span<T>
-Instanz den Speicher, auf den sie verweist, nicht kopieren.
Das verwerfbare Muster
Sie können eine verwerfbare ref struct
definieren. Stellen Sie dazu sicher, dass eine ref struct
dem Dispose-Muster entspricht. Das heißt, sie umfasst eine Instanzmethode Dispose
, auf die zugegriffen werden kann, die parameterlos ist und einen Rückgabetyp void
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 Regeln für die Verweissicherheit entspricht.
- Eine
ref struct
kann nicht in eine Instanz einer von ihr implementierten Schnittstelle konvertiert werden. Diese Einschränkung umfasst die implizite Konvertierung, wenn Sie einenref struct
-Typ als Argument verwenden, wenn der Parameter ein Schnittstellentyp ist. Die Konvertierung führt zu einer Boxing-Konvertierung, die gegen die Verweissicherheit verstößt. - Eine
ref struct
, die eine Schnittstelle implementiert, muss alle Schnittstellenmitglieder implementieren. Dieref struct
muss Mitglieder implementieren, in denen 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. Ihre Anwendung wird erst kompiliert, wenn Sie eine Implementierung für diese neuen Methoden bereitstellen.
Wichtig
Eine ref struct
, die eine Schnittstelle implementiert, kann später zu Änderungen führen, die den Quell- und Binärcode beeinträchtigen (Breaking Change). Dieser Fall tritt ein, wenn eine ref struct
eine in einer anderen Assembly definierte Schnittstelle implementiert und diese Assembly ein Update bereitstellt, das dieser Schnittstelle Standardmitglieder hinzufügt.
Der Breaking Change am Quellcode erfolgt, wenn Sie die ref struct
neu kompilieren: Sie muss das neue Mitglied implementieren, obwohl eine Standardimplementierung vorhanden ist.
Der Breaking Change am Binärcode erfolgt, wenn Sie die externe Assembly aktualisieren, ohne den ref struct
-Typ neu zu kompilieren, und der aktualisierte Code die Standardimplementierung der neuen Methode aufruft. 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.