Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Tipp
Neu bei der Entwicklung von Software? Beginnen Sie zuerst mit den Lernprogrammen " Erste Schritte ". Sobald Sie leichte Werttypen in Ihrem Code benötigen, werden Ihnen Strukturen begegnen.
Haben Sie Erfahrung in einer anderen Sprache? C#-Strukturen sind Werttypen, die den Strukturen in C++ oder Swift ähneln. Sie befinden sich jedoch auf dem verwalteten Heap, wenn sie "geboxt" werden und unterstützen dann Schnittstellen, Konstruktoren und Methoden. Überspringen Sie den Abschnitt "readonly structs " für C#-spezifische Muster. Informationen zu Datensatzstrukturen finden Sie unter "Datensätze".
Eine Struktur ist ein Werttyp, der seine Daten direkt in der Instanz und nicht über einen Verweis auf ein Objekt im Heap enthält. Wenn Sie einer neuen Variablen eine Struktur zuweisen, kopiert die Laufzeit die gesamte Instanz. Änderungen an einer Variablen wirken sich nicht auf die andere aus, da jede Variable eine andere Instanz darstellt. Verwenden Sie Strukturen für kleine, einfache Typen, deren primäre Rolle Daten speichert, anstatt das Verhalten zu modellieren. Beispiele sind Koordinaten, Farben, Maße oder Konfigurationseinstellungen.
Deklarieren einer Struktur
Definieren Sie eine Struktur mit dem struct Schlüsselwort. Eine Struktur kann Felder, Eigenschaften, Methoden und Konstruktoren wie eine Klasse enthalten:
struct Point
{
public double X { get; set; }
public double Y { get; set; }
public readonly double DistanceTo(Point other)
{
var dx = X - other.X;
var dy = Y - other.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
public override string ToString() => $"({X}, {Y})";
}
Die Point Struktur speichert zwei double Werte und stellt eine Methode zum Berechnen des Abstands zwischen zwei Punkten bereit. Die DistanceTo Methode ist markiert readonly , da sie den Zustand der Struktur nicht ändert. Dieses Muster wird in readonly-Elementen behandelt.
Wertsemantik
Strukturen sind Werttypen. Die Zuordnung kopiert die Daten, sodass jede Variable eine eigene unabhängige Kopie enthält:
var p1 = new Point { X = 3, Y = 4 };
var p2 = p1; // copies the data
p2.X = 10;
Console.WriteLine(p1); // (3, 4) — p1 is unchanged
Console.WriteLine(p2); // (10, 4) — only p2 was modified
Da es sich bei Strukturen um Datencontainer handelt, kopiert die Zuordnung jedes Datenelement in eine neue, unabhängige Instanz. Jede Kopie ist unterschiedlich. Eine Änderung wirkt sich nicht auf die andere aus. Dieses Verhalten unterscheidet sich von Klassen, bei denen zuordnung nur den Verweis kopiert und beide Variablen dasselbe Objekt gemeinsam verwenden. Weitere Informationen zur Unterscheidung finden Sie unter Werttypen und Referenztypen.
Strukturkonstruktoren
Sie können Konstruktoren auf die gleiche Weise wie in Klassen definieren. Strukturen können parameterlose Konstruktoren aufweisen, die benutzerdefinierte Standardwerte festlegen. Der Begriff "parameterloser Konstruktor" unterscheidet eine Instanz, die mit new erstellt wurde (die ihre Konstruktorlogik ausführt) von einer Standardinstanz die mit dem default Ausdruck erstellt wurde (wodurch alle Felder auf null initialisiert werden):
struct ConnectionSettings
{
public string Host { get; set; }
public int Port { get; set; }
public int MaxRetries { get; set; }
public ConnectionSettings()
{
Host = "localhost";
Port = 8080;
MaxRetries = 3;
}
}
Ein parameterloser Konstruktor wird ausgeführt, wenn Sie new ohne Argumente verwenden. Der default Ausdruck umgeht den Konstruktor und legt alle Felder auf ihre Standardwerte (0, , nullfalse). Beachten Sie den Unterschied:
var custom = new ConnectionSettings();
Console.WriteLine($"{custom.Host}:{custom.Port} (retries: {custom.MaxRetries})");
// localhost:8080 (retries: 3)
var defaults = default(ConnectionSettings);
Console.WriteLine($"{defaults.Host ?? "(null)"}:{defaults.Port} (retries: {defaults.MaxRetries})");
// (null):0 (retries: 0)
Der Compiler initialisiert automatisch alle Felder, die Sie nicht explizit in einem Konstruktor festlegen. Sie können nur die Felder initialisieren, die keine Standardwerte benötigen:
struct GameTile
{
public int Row { get; set; }
public int Column { get; set; }
public bool IsBlocked { get; set; }
public GameTile(int row, int column)
{
Row = row;
Column = column;
// IsBlocked is automatically initialized to false
}
}
var tile = new GameTile(2, 5);
Console.WriteLine($"Tile ({tile.Row}, {tile.Column}), blocked: {tile.IsBlocked}");
// Tile (2, 5), blocked: False
Die IsBlocked-Eigenschaft wird nicht im Konstruktor zugewiesen, daher setzt der Compiler sie auf false, was der Standardwert für bool ist. Dieses Feature reduziert den Standardcode in Konstruktoren, die nur wenige Felder setzen.
Schreibgeschützte Strukturen und schreibgeschützte Mitglieder
Dass readonly struct gewährleistet, dass kein Instanzmitglied den Zustand der Struktur verändert. Der Compiler stellt diese Garantie sicher, indem er verlangt, dass alle Felder und automatisch implementierten Eigenschaften schreibgeschützt sind:
readonly struct Temperature
{
public double Celsius { get; }
public Temperature(double celsius) => Celsius = celsius;
public double Fahrenheit => Celsius * 9.0 / 5.0 + 32.0;
public override string ToString() => $"{Celsius:F1}°C ({Fahrenheit:F1}°F)";
}
var temp = new Temperature(100);
Console.WriteLine(temp); // 100.0°C (212.0°F)
// temp.Celsius = 50; // Error: property is read-only
Wenn Sie nicht die gesamte Struktur benötigen, um unveränderlich zu sein, markieren Sie stattdessen einzelne Member als readonly Ein readonly Mitglied kann den Zustand der Struktur nicht ändern, und der Compiler überprüft, ob folgendes garantiert wird:
struct Velocity
{
public double X
{
readonly get;
set;
}
public double Y
{
readonly get;
set;
}
public readonly double Speed => Math.Sqrt(X * X + Y * Y);
public readonly override string ToString() => $"({X}, {Y}) speed={Speed:F2}";
}
var v = new Velocity { X = 3, Y = 4 };
Console.WriteLine(v.Speed); // 5
Console.WriteLine(v); // (3, 4) speed=5.00
v.X = 6;
Console.WriteLine(v.Speed); // 7.211...
Das Markieren von Membern readonly hilft dem Compiler, defensive Kopien zu optimieren. Wenn Sie eine Struktur an eine readonly Methode übergeben, die einen in Parameter akzeptiert, weiß der Compiler, dass keine Kopie erforderlich ist.
Wann man Strukturen verwenden sollte
Verwenden Sie beim Eingeben eine Struktur:
- Stellt einen einzelnen Wert oder eine kleine Gruppe verwandter Werte dar (ungefähr 16 Byte oder weniger).
- Hat Eine Wertsemantik – zwei Instanzen mit denselben Daten sollten gleich sein.
- Handelt es sich in erster Linie um einen Datencontainer und nicht um ein Verhaltensmodell.
- Benötigt keine Vererbung von einem Basistyp (Strukturen können nicht von anderen Strukturen oder Klassen erben, aber sie können Schnittstellen implementieren).
Einen umfassenderen Vergleich, der Klassen, Datensätze, Tupel und Schnittstellen enthält, finden Sie unter Auswählen der Art des Typs.