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.
A struktúratípus (vagy struktúratípus) olyan értéktípus , amely képes adatokat és kapcsolódó funkciókat beágyazni. A kulcsszóval struct
definiálhat egy struktúratípust:
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})";
}
Az ref struct
és readonly ref struct
típusokkal kapcsolatos információért lásd a struktúratípusok című cikket.
A struktúratípusok értékszemantikával rendelkeznek. Vagyis egy struktúratípus változója a típus egy példányát tartalmazza. Alapértelmezés szerint a változóértékek másolása hozzárendeléskor történik, argumentumot ad át egy metódusnak, és visszaad egy metóduseredményt. A struktúra típusú változók esetében a rendszer kimásolja a típus egy példányát. További információ: Értéktípusok.
Általában struktúratípusokat használunk kis adatcentrikus típusok tervezéséhez, amelyek kevés vagy egyáltalán semmilyen viselkedést nem biztosítanak. A .NET például struktúratípusokkal jelöl egy számot (egész és valós), logikai értéket, Unicode-karaktert és időpéldányt. Ha egy típus viselkedésére összpontosít, fontolja meg egy osztály definiálását. Az osztálytípusok referencia szemantikával rendelkeznek. Vagyis egy osztálytípus változója a típus egy példányára mutató hivatkozást tartalmaz, nem magát a példányt.
Mivel a struktúratípusok értékszemantikával rendelkeznek, javasoljuk, hogy definiáljon nem módosítható struktúratípusokat.
readonly
Struct
A módosító használatával readonly
deklarálhatja, hogy egy struktúratípus nem módosítható. A readonly
struktúrában az összes adattagnak írásvédettnek kell lennie az alábbiak szerint:
- Minden meződeklaráció rendelkezzen a
readonly
módosítóval. - Minden tulajdonságnak, beleértve az automatikusan végrehajtottakat is, írásvédettnek vagy
init
csak olvashatónak kell lennie. Az init-only setters csak C# 9-es verziójától érhető el.
Ez garantálja, hogy a szerkezet egyik readonly
tagja sem módosítja a szerkezet állapotát. Ez azt jelenti, hogy a konstruktorok kivételével más példánytagok is implicit módon readonly
vannak.
Feljegyzés
readonly
Egy strukturált szerkezetben egy mutable referenciatípus adattagja továbbra is képes saját állapotát mutálni. Például nem cserélhet le egy List<T> példapéldányt, de új elemeket adhat hozzá.
A következő kód egy readonly
csak init-only tulajdonsághalmazokkal rendelkező szerkezetet határoz meg:
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})";
}
readonly
példány objektum tagok
A módosító használatával readonly
azt is deklarálhatja, hogy egy példánytag nem módosítja a szerkezet állapotát. Ha nem deklarálhatja a teljes struktúratípust, readonly
a readonly
módosítóval megjelölheti azokat a példánytagokat, amelyek nem módosítják a szerkezet állapotát.
readonly
Egy példánytagon belül nem lehet hozzárendelni a struktúra példánymezőihez. Egy readonly
tag azonban meghívhat egy nem-readonly
tagot. Ebben az esetben a fordító létrehozza a struktúrapéldány egy példányát, és meghívja a nem tagotreadonly
a példányon. Ennek eredményeképpen az eredeti struktúrapéldány nem módosul.
Általában a következő típusú példánytagokra alkalmazza a readonly
módosítót:
Módszerek:
public readonly double Sum() { return X + Y; }
Alkalmazhatja a
readonly
módosítót olyan metódusokra is, amelyek felülírják a System.Object-ben deklarált metódusokat.public readonly override string ToString() => $"({X}, {Y})";
tulajdonságok és indexelők:
private int counter; public int Counter { readonly get => counter; set => counter = value; }
Ha egy tulajdonság vagy indexelő mindkét tartozékára alkalmaznia kell a
readonly
módosítót, alkalmazza azt a tulajdonság vagy indexelő deklarációjában.Feljegyzés
A fordító egy
get
hozzáférőt deklarál egy automatikusan implementált tulajdonsághozreadonly
, függetlenül attól, hogy areadonly
módosító szerepel-e a tulajdonság deklarációjában.A
readonly
módosítót egyinit
tartozékkal rendelkező tulajdonságra vagy indexelőre alkalmazhatja:public readonly double X { get; init; }
A módosító egy readonly
struktúratípus statikus mezőire alkalmazható, más statikus tagokra, például tulajdonságokra vagy metódusokra nem.
A fordító a teljesítményoptimalizáláshoz használhatja a readonly
módosítót. További információt talál a foglalások elkerülése című témakörben.
Romboló hatás nélküli mutáció
A with
kifejezés használatával másolatot készíthet egy struktúra típusú példányról a megadott tulajdonságok és mezők módosításával. Az objektum inicializáló szintaxisát használja annak megadására, hogy mely tagokat kívánja módosítani és azok új értékeit, ahogy az alábbi példa mutatja:
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)
}
record
Struct
Megadhatja a rekordstruktúra típusait. A rekordtípusok beépített funkciókat biztosítanak az adatok beágyazására. Mind a record struct
, mind a readonly record struct
típust meghatározhatja. A rekordstruktúra nem lehet ref struct
. További információkért és példákért lásd a Rekordok című témakört.
Beágyazott tömbök
A C# 12-től kezdődően a inline tömböket típusként deklarálhatja:struct
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
A beágyazott tömb olyan struktúra, amely azonos típusú N elemek egybefüggő blokkját tartalmazza. Ez a rögzített pufferdeklaráció biztonságos kódjának megfelelője, amely csak nem biztonságos kódban érhető el. Egy beágyazott tömb struct
a következő jellemzőkkel rendelkezik:
- Egyetlen mezőt tartalmaz.
- A szerkezet nem határoz meg explicit elrendezést.
Emellett a fordító ellenőrzi az System.Runtime.CompilerServices.InlineArrayAttribute attribútumot:
- A hossznak nullánál (
> 0
) nagyobbnak kell lennie. - A céltípusnak egy szerkezetnek kell lennie.
A legtöbb esetben a soros tömb elérhető úgy, mint egy hagyományos tömb, mind az olvasáshoz, mind az íráshoz. Emellett használhatja a tartomány - és index operátorokat is.
A beágyazott tömb egyetlen mezőjének típusára minimális korlátozások vonatkoznak. Nem lehet mutatótípus:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
De lehet bármilyen referenciatípus, vagy bármilyen értéktípus:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
A beágyazott tömbök szinte bármilyen C#-adatstruktúrával használhatók.
Az inline tömbök haladó nyelvi funkciók. Nagy teljesítményű forgatókönyvekhez készültek, ahol egy beágyazott, összefüggő elemblokk gyorsabb, mint más alternatív adatstruktúrák. A beágyazott tömbökről a funkciós specifikációcímű cikkből tudhat meg több információt.
Szerkezet inicializálása és alapértelmezett értékei
Egy típus változója struct
közvetlenül tartalmazza az ehhez struct
tartozó adatokat. Ez különbséget tesz egy nem inicializált struct
között, amely az alapértelmezett értékét tartalmazza, valamint egy inicializált struct
között, amely az általa konfigurált értékeket tárolja. Vegyük például a következő kódot:
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 ()
}
Ahogy az előző példa is mutatja, az alapértelmezett értékkifejezés figyelmen kívül hagy egy paraméter nélküli konstruktort, és létrehozza a struktúratípus alapértelmezett értékét . A struktúra típusú tömbök példányosítása szintén figyelmen kívül hagy egy paraméter nélküli konstruktort, és létrehoz egy olyan tömböt, amely egy struktúratípus alapértelmezett értékeivel van feltöltve.
Az alapértelmezett értékek leggyakrabban tömbökben vagy más gyűjteményekben találhatók, ahol a belső tároló változóblokkokat tartalmaz. Az alábbi példa egy 30 TemperatureRange
struktúrából álló tömböt hoz létre, amelyek mindegyike az alapértelmezett értékkel rendelkezik:
// All elements have default values of 0:
TemperatureRange[] lastMonth = new TemperatureRange[30];
Az összes tagmezőt mindenképpen hozzá kell rendelni létrehozásakor, mert struct
típusok közvetlenül tárolják az adataikat. Egy struktúra default
értéke minden mezőhöz 0-hoz van hozzárendelve. Minden mezőt mindenképpen hozzá kell rendelni egy konstruktor meghívásakor. A mezők inicializálása az alábbi mechanizmusokkal történik:
- Bármilyen mező- vagy automatikusan implementált tulajdonsághoz hozzáadhat mező inicializálókat .
- A konstruktor törzsében bármilyen mezőt vagy automatikus tulajdonságot inicializálhat.
A C# 11-től kezdődően, ha nem inicializálja a szerkezet összes mezőjét, a fordító kódot ad hozzá a konstruktorhoz, amely inicializálja ezeket a mezőket az alapértelmezett értékhez. A default
értékhez rendelt struktúra inicializálva van a 0-bites mintázatra. A new
értékkel inicializált struktúra nullás bitmintára van inicializálva, amit a mező inicializálók és egy konstruktor végrehajtása követ.
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 ()
}
Minden struct
rendelkezik egy public
paraméter nélküli konstruktorral. Ha paraméter nélküli konstruktort ír, annak nyilvánosnak kell lennie. Ha egy szerkezet bármilyen mező inicializálót deklarál, explicit módon konstruktort kell deklarálnia. A konstruktornak nem kell paraméter nélkülinek lennie. Ha egy szerkezet deklarál egy mező inicializálót, de konstruktorokat nem, a fordító hibát jelez. Bármely explicit módon deklarált konstruktor (paraméterekkel vagy paraméter nélküliekkel) végrehajtja az adott struktúra összes mező inicializálóját. A mező inicializálója vagy a konstruktorban lévő hozzárendelés nélküli mezők az alapértelmezett értékre vannak beállítva. További információ: Paraméter nélküli szerkezetkonstruktorok funkciójavaslat megjegyzése.
A C# 12-től struct
kezdődően a típusok meghatározhatnak egy elsődleges konstruktort a deklaráció részeként. Az elsődleges konstruktorok tömör szintaxist biztosítanak a konstruktorparaméterekhez, amelyek az struct
törzsben, az adott szerkezet bármely tagdeklarációjában használhatók.
Ha egy struktúratípus összes példánymezője elérhető, akkor az new
operátor nélkül is példányosíthatja. Ebben az esetben a példány első használata előtt inicializálnia kell az összes példánymezőt. Az alábbi példa bemutatja, hogyan teheti ezt meg:
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)
}
}
A beépített értéktípusokesetében a megfelelő literálokkal adja meg a típus értékét.
A struktúratípus kialakítására vonatkozó korlátozások
A szerkezetek az osztálytípus legtöbb képességével rendelkeznek. Vannak kivételek:
- Egy struktúratípus nem örökölhető más osztálytól vagy struktúratípustól, és nem lehet egy osztály alapja. A struktúratípusok azonban implementálhatnak interfészeket.
- Szerkezettípuson belül nem deklarálhat véglegesítőt .
- A C# 11 előtt egy struktúratípus konstruktorának inicializálnia kell a típus összes példánymezőit.
Struktúra típusú változók átadása hivatkozás alapján
Ha egy struktúra típusú változót argumentumként ad át egy metódusnak, vagy egy metódusból ad vissza egy struktúra típusú értéket, a rendszer átmásolja a struktúratípus teljes példányát. Az érték szerinti átadás befolyásolhatja a kód teljesítményét nagy teljesítményű esetekben, amelyek nagy struktúratípusokat foglalnak magukban. Az értékmásolást elkerülheti egy struktúra típusú változó hivatkozással történő átadásával.
ref
, out
, in
, vagy ref readonly
metódusparaméter-módosítókat használja annak jelzésére, hogy egy argumentumot hivatkozással kell átadni. Használja a ref returneket, hogy egy metódus eredményét hivatkozással adja vissza. További információért lásd: A foglalások elkerülése.
struct
korlátozás
A kényszerbenstruct
struct
kulcsszóval azt is megadhatja, hogy egy típusparaméter nem null értékű típus-e. A struktúra és az enumerálási típusok egyaránt megfelelnek a kényszernek struct
.
Konverziók
Bármilyen struktúratípus esetében (kivéve ref struct
típusokat) léteznek boxing és unboxing konverziók, amelyek System.ValueType és System.Object típusok között történhetnek. Léteznek boxing és unboxing konverziók egy struktúratípus és bármely interfész között, amelyet a struktúratípus implementál.
C# nyelvspecifikáció
További információkért lásd a C#-nyelv specifikációjának Structs szakaszát.
A funkciókkal kapcsolatos struct
további információkért tekintse meg a következő funkciókra vonatkozó javaslati megjegyzéseket:
- Olvasható szerkezetek
- Csak olvasható példánytagok
- paraméter nélküli szerkezetkonstruktorok
-
with
kifejezés engedélyezése a szerkezeteken - Rekordstrukturák
- Automatikus alapértelmezett struktúrák