Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Jótanács
Új szoftverfejlesztés? Először az Első lépések oktatóanyagokkal kezdje. Ha egyszerűsített értéktípusokra van szüksége a kódban, a szerkezetekkel találkozik.
Tapasztalt egy másik nyelven? A C# struktúrák olyan értéktípusok, amelyek hasonlóak a C++ vagy Swift struktúrákhoz, de amikor dobozolva vannak, a felügyelt halmon helyezkednek el, és támogatják a felületeket, konstruktorokat és metódusokat. A C#-specifikus minták olvasható szerkezetek szakaszának átfésülése. A rekordstruktúra a Rekordok című témakörben olvasható.
A szerkezet olyan értéktípus, amely közvetlenül a példányban tárolja az adatait, nem pedig a halom egy objektumára mutató hivatkozáson keresztül. Amikor új változóhoz rendel egy szerkezetet, a futtatókörnyezet a teljes példányt átmásolja. Az egyik változó módosítása nincs hatással a másikra, mert mindegyik változó egy másik példányt jelöl. Szerkezetek használata olyan kisméretű, egyszerűsített típusokhoz, amelyek elsődleges szerepe az adatok tárolása a modellezési viselkedés helyett. Ilyenek például a koordináták, a színek, a mérések vagy a konfigurációs beállítások.
Mikor érdemes használni a szerkezeteket?
Használjon struktúrát, ha a típus:
- Egyetlen értéket vagy a kapcsolódó értékek kis csoportját jelöli (nagyjából 16 bájt vagy kevesebb).
- Értékszemantikával rendelkezik – két azonos adattal rendelkező példánynak egyenlőnek kell lennie.
- Ez elsősorban egy adattároló, nem pedig egy viselkedési modell.
- Nem igényel öröklést egy alaptípusból (a szerkezetek nem örökölhetnek más szerkezetektől vagy osztályoktól, de interfészeket implementálhatnak).
Az osztályokat, rekordokat, tuple-öket és interfészeket tartalmazó szélesebb körű összehasonlításért tekintse meg a Típus kiválasztása című témakört.
Deklarálj egy struktúrát
Adjon meg egy szerkezetet a struct kulcsszóval. A szerkezetek ugyanúgy tartalmazhatnak mezőket, tulajdonságokat, metódusokat és konstruktorokat, mint egy osztályt:
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})";
}
A Point szerkezet két double értéket tárol, és egy metódust biztosít a két pont közötti távolság kiszámításához. A DistanceTo metódus azért van megjelölve readonly , mert nem módosítja a szerkezet állapotát. Ezt a mintát olvasható tagok fedik le.
Érték szemantikája
A szerkezetek értéktípusok. A hozzárendelés átmásolja az adatokat, így minden változó saját független másolatot tartalmaz:
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
Mivel a szerkezetek adattárolók, a hozzárendelés minden adattagot egy új, független példányba másol. Minden másolat eltérő. Az egyik módosítása nincs hatással a másikra. Ez a viselkedés eltér az osztályoktól, ahol a hozzárendelés csak a hivatkozást másolja, és mindkét változó ugyanazt az objektumot használja. A megkülönböztetésről további információt az Értéktípusok és a referenciatípusok című témakörben talál.
Szerkezetkonstruktorok
Konstruktorokat ugyanúgy definiálhat a szerkezetekben, mint az osztályokban. A szerkezetek paraméter nélküli konstruktorokkal is rendelkezhetnek, amelyek egyéni alapértelmezett értékeket állíthatnak be. A "paraméter nélküli konstruktor" kifejezés megkülönbözteti a konstruktorlogikát new futtató példányt a kifejezéssel létrehozott default példánytól (amely az összes mezőt nullával inicializálja):
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;
}
}
Paraméter nélküli konstruktor akkor fut, ha argumentumok nélkül használja new . A default kifejezés megkerüli a konstruktort, és beállítja az összes mezőt az alapértelmezett értékekre (0, null, false). Vegye figyelembe a különbséget:
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)
A fordító automatikusan inicializálja a konstruktorban nem explicit módon beállított mezőket. Csak azokat a mezőket inicializálhatja, amelyek nem alapértelmezett értékeket igényelnek:
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
}
}
Az alábbi példa a következő alapértelmezett értéket IsBlockedjeleníti meg:
var tile = new GameTile(2, 5);
Console.WriteLine($"Tile ({tile.Row}, {tile.Column}), blocked: {tile.IsBlocked}");
// Tile (2, 5), blocked: False
A IsBlocked tulajdonság nincs hozzárendelve a konstruktorban, ezért a fordító false értékre állítja (ami az alapértelmezett bool esetén). Ez a funkció csökkenti a konstruktorokban a sablonkódot, amelyeknek csak néhány mezőt kell beállítaniuk.
Csak olvasható struktúrák és csak olvasható tagok
Garantálja, hogy a readonly struct egyetlen példánytag sem módosítja a struktúra állapotát. A fordító ezt a garanciát úgy érvényesíti, hogy az összes mezőnek és az automatikusan implementált tulajdonságnak írásvédettnek kell lennie.
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)";
}
Az alábbi példa létrehoz egy Temperature példányt, és beolvassa annak tulajdonságait.
var temp = new Temperature(100);
Console.WriteLine(temp); // 100.0°C (212.0°F)
// temp.Celsius = 50; // Error: property is read-only
Ha nincs szüksége a teljes szerkezetre, hogy megváltoztathatatlan legyen, jelölje meg az egyes tagokat readonly helyette. A readonly tag nem tudja módosítani a szerkezet állapotát, és a fordító ellenőrzi, hogy a következő garancia van-e:
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}";
}
Az alábbi példa azt mutatja be, hogy a readonly tagok frissített értékeket adnak vissza a változó tulajdonságok változásakor:
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...
A readonly tagok megjelölésével segíthetünk a fordítónak a védelmi másolatok optimalizálásában. Amikor egy paramétert elfogadó readonly metódusnak ad át egy in szerkezetet, a fordító tudja, hogy nincs szükség másolatra.