Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
A struktúratípus (vagy struktúratípus) olyan értéktípus , amely képes adatokat és kapcsolódó funkciókat beágyazni.
A C# nyelv referenciadokumentuma a C# nyelv legújabb kiadású verzióját ismerteti. Emellett a közelgő nyelvi kiadás nyilvános előzetes verziójú funkcióinak kezdeti dokumentációját is tartalmazza.
A dokumentáció azonosítja azokat a funkciókat, amelyeket először a nyelv utolsó három verziójában vagy az aktuális nyilvános előzetes verziókban vezetnek be.
Jótanács
Ha meg szeretné tudni, hogy mikor jelent meg először egy funkció a C#-ban, tekintse meg a C# nyelvi verzióelőzményeiről szóló cikket.
struct A kulcsszóval 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. A rendszer alapértelmezés szerint a hozzárendelés változóértékeket másol, amikor argumentumot ad át egy metódusnak, és amikor visszaad egy metóduseredményt. A struktúra típusú változók esetében a rendszer a típus egy példányát másolja. 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ípusokat használ egy szám (egész ésvalós), logikai érték, Unicode-karakter és időpéldány ábrázolására. 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
readonly A módosító használatával 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
readonlymódosítóval. - Minden tulajdonságnak, beleértve az automatikusan végrehajtottakat is, írásvédettnek vagy
initcsak olvashatónak kell lennie. Az init-only setters csak C# 9-es verziójától érhető el.
Ez a szabály garantálja, hogy a szerkezet egyik readonly tagja sem módosítja a szerkezet állapotát. A konstruktorok kivételével minden más példánytag implicit módon readonlyvan.
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
readonly A módosító használatával deklarálhatja, hogy egy példánytag nem módosítja a szerkezet állapotát. Ha nem deklarálhatja a teljes struktúratípust, readonlya 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 rendelhető hozzá 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
readonlymó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
readonlymódosítót, alkalmazza azt a tulajdonság vagy indexelő deklarációjában.Feljegyzés
A fordító egy automatikusan implementált tulajdonság
readonlytartozékát deklaráljaget, függetlenül attól, hogy a módosító szerepel-e areadonlytulajdonságdeklarációban.A
readonlymódosítót egyinittartozé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ó
with A kifejezéssel létrehozhatja egy struktúra típusú példány másolatát a megadott tulajdonságok és mezők módosításával. Az objektum inicializáló szintaxisával megadhatja, hogy mely tagok és az új értékek módosíthatók, ahogy az alábbi példa is 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 kezdve a beágyazott tömböket típusként struct deklarálhatja:
[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 egy beágyazott tömbhöz, például tömbhöz is hozzáférhet az értékek olvasásához és írásához. A tartomány - és indexoperátorok is használhatók.
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ó specifikációjából tudhat meg többet.
Szerkezet inicializálása és alapértelmezett értékei
Egy típus változója struct közvetlenül tartalmazza az ehhez structtartozó adatokat. Ez a közvetlen adattárolás különbséget tesz az alapértelmezett értékkel rendelkező, nem inicializált structés az inicializált structértékek között, amelyek a létrehozásukkal tárolják a beállított értékeket. 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. A default szerkezet értéke mindenképpen 0-hoz rendeli az összes mezőt. 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:
- Adjon hozzá mező inicializálókat bármely mezőhöz vagy automatikusan implementált tulajdonsághoz.
- Inicializálja a konstruktor törzsében lévő mezőket vagy automatikus tulajdonságokat.
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 .
- 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
struct A kényszerben szereplőstruct kulcsszóval 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 a típusokat), a dobozolás és a dobozolás törlése a típusokra és System.Object típusokra System.ValueType való és onnan érkező konverziókra is létezik. A boxing és a unboxing konverziók is léteznek a struktúratípus és az általa implementálható felületek között.
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
-
withkifejezés engedélyezése a szerkezeteken - Rekordstrukturák
- Automatikus alapértelmezett struktúrák