Ereignisse
17. März, 21 Uhr - 21. März, 10 Uhr
Nehmen Sie an der Meetup-Serie teil, um skalierbare KI-Lösungen basierend auf realen Anwendungsfällen mit Mitentwicklern und Experten zu erstellen.
Jetzt registrierenDieser Browser wird nicht mehr unterstützt.
Führen Sie ein Upgrade auf Microsoft Edge aus, um die neuesten Funktionen, Sicherheitsupdates und technischen Support zu nutzen.
Ein Strukturtyp (oder struct type) ist ein Werttyp, der Daten und zugehörige Funktionen kapseln kann. Verwenden Sie das struct
-Schlüsselwort, um einen Strukturtyp zu definieren:
public struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
public override string ToString() => $"({X}, {Y})";
}
Informationen zu ref struct
- und readonly ref struct
-Typen finden Sie im Artikel Verweisstrukturtypen.
Strukturtypen verfügen über eine Wertsemantik. Das heißt, eine Variable eines Strukturtyps enthält eine Instanz des Typs. Standardmäßig werden die Variablenwerte bei der Zuweisung kopiert, dabei handelt es sich um die Übergabe eines Arguments an eine Methode oder die Rückgabe eines Methodenergebnisses. Für Strukturtypvariablen wird eine Instanz des Typs kopiert. Weitere Informationen finden Sie unter Werttypen.
In der Regel werden Strukturtypen zum Entwerfen kleiner datenorientierter Typen verwendet, die wenig oder gar kein Verhalten bereitstellen. Beispielsweise verwendet .NET Strukturtypen, um Zahlen (sowohl Integer als auch reelle Zahlen), boolesche Werte, Unicode-Zeichen und Zeitinstanzen darzustellen. Wenn Sie das Verhalten eines Typs verwenden möchten, sollten Sie eine Klasse definieren. Klassentypen verfügen über Verweissemantik. Das heißt, eine Variable eines Klassentyps enthält einen Verweis auf eine Instanz des Typs, nicht die Instanz selbst.
Da Strukturtypen eine Wertsemantik aufweisen, wird die Definition von unveränderlichen Strukturtypen empfohlen.
Sie können mit dem readonly
-Modifizierer einen Strukturtyp als unveränderlich deklarieren. Alle Datenmember einer readonly
-Struktur müssen als schreibgeschützt gekennzeichnet sein:
readonly
Modifiziererverfügen.init
nur schreibgeschützt sein. Init-only-Setter sind nur verfügbar von C# Version 9 aufwärts.Auf diese Weise ist garantiert, dass kein Member einer readonly
-Struktur den Status der Struktur ändert. Das bedeutet, dass andere Instanzmember mit Ausnahme von Konstruktoren implizit readonly
werden.
Hinweis
In einer readonly
-Struktur kann ein Datenmember eines änderbaren Verweistyps weiterhin den eigenen Status ändern. Beispielsweise können Sie eine List<T>-Instanz nicht ersetzen, aber neue Elemente zur Instanz hinzufügen.
Der folgende Code definiert eine readonly
-Struktur mit Nur-init-Eigenschaftensettern, die in C# 9.0 und höher verfügbar sind:
public readonly struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; init; }
public double Y { get; init; }
public override string ToString() => $"({X}, {Y})";
}
Sie können auch den readonly
-Modifizierer verwenden, um zu deklarieren, dass ein Instanzmember den Zustand einer Struktur nicht ändert. Wenn Sie nicht den gesamten Strukturtyp als readonly
deklarieren können, verwenden Sie den readonly
-Modifizierer, um die Instanzmember zu markieren, die den Zustand der Struktur nicht ändern.
Innerhalb eines readonly
-Instanzmembers können Sie den Instanzfeldern einer Struktur nichts zuweisen. Ein readonly
-Member kann jedoch ein Nicht-readonly
-Member aufrufen. In diesem Fall erstellt der Compiler eine Kopie der Strukturinstanz und ruft den Nicht-readonly
-Member in dieser Kopie auf. Folglich wird die ursprüngliche Strukturinstanz nicht geändert.
In der Regel wenden Sie den readonly
-Modifizierer auf die folgenden Arten von Instanzmembern an:
Methoden:
public readonly double Sum()
{
return X + Y;
}
Sie können den readonly
-Modifizierer auch auf Methoden anwenden, die in System.Object deklarierte Methoden überschreiben:
public readonly override string ToString() => $"({X}, {Y})";
Eigenschaften und Indexer:
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
Wenn Sie den readonly
-Modifizierer auf die Accessoren sowohl einer Eigenschaft als auch eines Indexers anwenden müssen, wenden Sie ihn in der Deklaration der Eigenschaft bzw. des Indexers an.
Hinweis
Der Compiler deklariert einen get
Accessor einer automatisch implementierten Eigenschaft als readonly
, unabhängig vom Vorhandensein des readonly
Modifizierers in einer Eigenschaftsdeklaration.
Sie können die readonly
Modifikator an eine Eigenschaft oder einen Indexer mit einer init
Zugriff:
public readonly double X { get; init; }
Sie können den readonly
-Modifizierer auf statische Felder eines Strukturtyps anwenden, aber nicht auf andere statische Member, z. B. Eigenschaften oder Methoden.
Der Compiler kann den readonly
-Modifizierer für Leistungsoptimierungen verwenden. Weitere Informationen finden Sie unter Vermeiden von Reservierungen.
Sie können die with
Ausdruck um eine Kopie einer strukturartigen Instanz zu erzeugen, bei der die angegebenen Eigenschaften und Felder geändert wurden. Sie verwenden die Objektinitialisierersyntax, um anzugeben, welche Member bearbeitet und welche neuen Werte dazu verwendet werden sollen, wie im folgenden Beispiel gezeigt:
public readonly struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; init; }
public double Y { get; init; }
public override string ToString() => $"({X}, {Y})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
Sie können Datensatzstrukturtypen definieren. Datensatztypen bieten integrierte Funktionen zum Kapseln von Daten. Sie können sowohl record struct
- als auch readonly record struct
-Typen definieren. Eine Datensatzstruktur kann kein ref struct
sein. Weitere Informationen und Beispiele finden Sie unter Datensätze.
Ab C# 12 können Sie Inlinearrays als Typ struct
deklarieren:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
Ein Inlinearray ist eine Struktur, die einen zusammenhängenden Block von N-Elementen desselben Typs enthält. Es ist ein Äquivalent der Deklaration eines festen Puffers, die nur in unsicherem Code verfügbar ist. Ein Inlinearray ist ein struct
mit den folgenden Merkmalen:
Darüber hinaus überprüft der Compiler das Attribut System.Runtime.CompilerServices.InlineArrayAttribute:
> 0
) sein.In den meisten Fällen kann auf ein Inlinearray wie ein Array zugegriffen werden, um Werte zu lesen und zu schreiben. Darüber hinaus können Sie die Operatoren Bereich und Index verwenden.
Es gibt minimale Einschränkungen für den Typ des einzelnen Felds eines Inlinearrays. Es kann kein Zeigertyp sein:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
Dabei kann es sich jedoch um einen beliebigen Verweistyp oder einen beliebigen Werttyp handeln:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
Sie können Inlinearrays mit fast jeder C#-Datenstruktur verwenden.
Inlinearrays sind ein erweitertes Sprachfeature. Sie sind für Hochleistungsszenarien vorgesehen, in denen ein inline zusammenhängender Block von Elementen schneller ist als andere alternative Datenstrukturen. Weitere Informationen zu Inlinearrays finden Sie im Feature-Speclet.
Eine Variable eines struct
-Typs enthält direkt die Daten für die betreffende struct
. Dadurch wird unterschieden zwischen einer nicht initialisierten struct
, die einen Standardwert hat, und einer initialisierten struct
, in der Werte gespeichert werden, die durch die Erstellung festgelegt wurden. Betrachten Sie beispielsweise den folgenden Code:
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
Wie das obige Beispiel zeigt, ignoriert der Standardwertausdruck einen parameterlosen Konstruktor und erzeugt den Standardwert des Strukturtyps. Bei der Instanziierung des Strukturtyparrays wird ein parameterloser Konstruktor ebenfalls ignoriert und ein Array erzeugt, das mit den Standardwerten eines Strukturtyps aufgefüllt wird.
Die häufigste Situation, in der Standardwerte verwendet werden, sind Arrays oder andere Auflistungen, in denen der interne Speicher Blöcke von Variablen enthält. Im folgenden Beispiel wird ein Array von 30 TemperatureRange
-Strukturen erstellt, die jeweils den Standardwert aufweisen:
// All elements have default values of 0:
TemperatureRange[] lastMonth = new TemperatureRange[30];
Alle Mitgliedsfelder einer Struktur müssen eindeutig zugeordnet bei der Erstellung, weil struct
Typen ihre Daten direkt speichern. Die default
Wert einer Struktur eindeutig zugeordnet alle Felder auf 0. Alle Felder müssen definitiv zugewiesen werden, wenn ein Konstruktor aufgerufen wird. Sie initialisieren Felder mit den folgenden Mechanismen:
Wenn Sie ab C# 11 nicht alle Felder in einer Struktur initialisieren, fügt der Compiler dem Konstruktor Code hinzu, der diese Felder mit dem Standardwert initialisiert. Eine Struktur, die ihrer default
Wert wird mit dem 0-Bit-Muster initialisiert. Eine Zeichenkette, initialisiert mit new
wird mit dem 0-Bit-Muster initialisiert, gefolgt von der Ausführung aller Feldinitialisierer und eines Konstruktors.
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
Jede struct
verfügt über einen parameterlosen public
-Konstruktor. Wenn Sie einen parameterlosen Konstruktor schreiben, muss dieser öffentlich sein. Wenn eine Struktur Feldinitialisierer deklariert, muss sie explizit einen Konstruktor deklarieren. Der betreffende Konstruktor muss nicht parameterlos sein. Wenn eine Struktur einen Feldinitialisierer, aber keine Konstruktoren deklariert, meldet der Compiler einen Fehler. Jeder explizit deklarierte Konstruktor (mit oder ohne Parameter) führt alle Feldinitialisierer für die betreffende Struktur aus. Alle Felder ohne Feldinitialisierer oder Zuweisung in einem Konstruktor werden auf den Standardwert festgelegt. Weitere Informationen finden Sie im Featurevorschlagshinweis für parameterlose Strukturkonstruktoren.
Ab C# 12 können struct
-Typen einen primären Konstruktor als Teil der Deklaration definieren. Primäre Konstruktoren bieten eine prägnante Syntax für Konstruktorparameter, die in der gesamten Software verwendet werden können. struct
Körper, in jeder Member-Deklaration für diese Struktur.
Wenn alle Instanzfelder eines Strukturtyps zugänglich sind, können Sie ihn auch ohne den new
-Operator instanziieren. In diesem Fall müssen Sie alle Instanzfelder vor der ersten Verwendung der Instanz initialisieren. Das folgende Beispiel zeigt, wie Sie dabei vorgehen müssen:
public static class StructWithoutNew
{
public struct Coords
{
public double x;
public double y;
}
public static void Main()
{
Coords p;
p.x = 3;
p.y = 4;
Console.WriteLine($"({p.x}, {p.y})"); // output: (3, 4)
}
}
Für die eingebaute Wertetypen, verwenden Sie die entsprechenden Literale, um einen Wert des Typs anzugeben.
Strukturen verfügen über die meisten Funktionen eines Klassentyps. Es gibt einige Ausnahmen:
Wenn Sie eine Strukturtypvariable als Argument an eine Methode übergeben oder einen Strukturtypvariable einer Methode zurückgeben, wird die gesamte Instanz des Strukturtyps kopiert. Die Wertübergabe nach Wert kann sich in Hochleistungsszenarios mit großen Strukturtypen auf die Leistung Ihres Codes auswirken. Sie können das Kopieren von Werten vermeiden, indem Sie eine Strukturtypvariable als Verweis übergeben. Verwenden Sie die Methodenparametermodifizierer ref
, out
, in
oder ref readonly
um anzugeben, dass ein Argument als Verweis übergeben werden muss. Verwenden Sie ref returns, um ein Methodenergebnis als Verweis zurückzugeben. Weitere Informationen finden Sie unter Vermeiden von Reservierungen.
Sie können auch das struct
-Schlüsselwort in der struct
-Einschränkung verwenden, um anzugeben, dass ein Typparameter ein Non-Nullable-Werttyp ist. Sowohl Struktur- als auch Enumerationstypen erfüllen die struct
-Einschränkung.
Für alle Strukturtypen (außer ref struct
-Typen) gibt es Boxing- und Unboxing-Umwandlungen in und aus den Typen System.ValueType und System.Object. Außerdem gibt es Boxing- und Unboxing-Umwandlungen zwischen einem Strukturtyp und der Schnittstelle, die ihn implementiert.
Weitere Informationen finden Sie im Abschnitt Strukturen der C#-Sprachspezifikation.
Weitere Informationen zu struct
-Features finden Sie in den folgenden Featurevorschlägen:
Feedback zu .NET
.NET ist ein Open Source-Projekt. Wählen Sie einen Link aus, um Feedback zu geben:
Ereignisse
17. März, 21 Uhr - 21. März, 10 Uhr
Nehmen Sie an der Meetup-Serie teil, um skalierbare KI-Lösungen basierend auf realen Anwendungsfällen mit Mitentwicklern und Experten zu erstellen.
Jetzt registrieren