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.
16.1 Általános
A szerkezetek hasonlóak az osztályokhoz, amelyek adatstruktúrákat jelölnek, amelyek adattagokat és függvénytagokat tartalmazhatnak. Az osztályoktól eltérően azonban a szerkezetek értéktípusok, és nem igényelnek halomfoglalást. Egy típus változója struct
közvetlenül tartalmazza a típus adatait struct
, míg egy osztálytípus változója az adatokra mutató hivatkozást, az utóbbit objektumnak nevezik.
Megjegyzés: A szerkezetek különösen hasznosak az értékszemantikával rendelkező kis adatstruktúrák esetében. Az összetett számok, a koordinátarendszer pontjai vagy a szótár kulcs-érték párjai mind jó példák a szerkezetekre. Ezeknek az adatstruktúráknak az a legfontosabb, hogy kevés adattagjuk van, és nem igényelnek öröklési vagy hivatkozási szemantikát, hanem kényelmesen implementálhatók értékszemantikával, ahol a hozzárendelés a hivatkozás helyett az értéket másolja. végjegyzet
A 8.3.5. §-ban leírtak szerint a C# által biztosított egyszerű típusok, például int
a , double
és bool
, valójában az összes strukturált típus.
16.2 Szerkezetmegjelölő nyilatkozatok
16.2.1 Általános
A struct_declaration egy type_declaration (14.7. §), amely új szerkezetet deklarál:
struct_declaration
: attributes? struct_modifier* 'ref'? 'partial'? 'struct'
identifier type_parameter_list? struct_interfaces?
type_parameter_constraints_clause* struct_body ';'?
;
A struct_declaration egy választható attribútumkészletből(22. §) áll, amelyet struct_modifierválasztható készlet követ (16.2.2. §), majd egy választható ref
módosító (16.2.3. §), majd egy választható részleges módosító (15.2.7. §), amelyet a kulcsszó struct
és a szerkezetnek nevező azonosító követ, és egy opcionális type_parameter_list specifikáció (15.2.3.), majd egy választható struct_interfaces specifikáció (16.2.5.§), majd egy opcionális type_parameter_constraints-záradék specifikáció (15.2.5. §), majd egy struct_body (16.2.6. §), amelyet opcionálisan pontosvessző követ.
A struktúra deklaráció nem adhat meg type_parameter_constraints_clause-okat, hacsak nem ad meg type_parameter_list-et is.
A type_parameter_list ellátó strukturált deklaráció általános szerkezet deklaráció. Ezenkívül az általános osztálydeklarációkba vagy általános szerkezetdeklarációkba ágyazott szerkezetek maguk is általános szerkezet deklarációk, mivel a szerkezetezett típus létrehozásához meg kell adni a típus argumentumait (8.4. §).
A kulcsszót ref
tartalmazó strukturált deklarációnak nem lehet struct_interfaces része.
16.2.2 Szerkezetmódosítók
A struct_declaration opcionálisan struct_modifiersorozatot is tartalmazhatnak:
struct_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| 'readonly'
| unsafe_modifier // unsafe code support
;
unsafe_modifier (23.2. §) csak nem biztonságos kódban érhető el (23. §).
Fordítási idő hibája, hogy ugyanaz a módosító többször is megjelenik egy szerkezetdeklarációban.
readonly
A szerkezetmegjelölő deklaráció módosítóinak jelentése nem azonos az osztálydeklarációéval (15.2.2. §).
A readonly
módosító azt jelzi, hogy a struct_declaration olyan típust deklarál, amelynek példányai nem módosíthatók.
Az olvasható szerkezetek a következő korlátozásokkal rendelkeznek:
- Az egyes példánymezőket is deklarálni
readonly
kell . - Nem deklarál semmilyen mezőszerű eseményt (15.8.2. §).
Ha egy egyszerű szerkezet egy példányát egy metódusnak ad át, a this
rendszer bemeneti argumentumként/paraméterként kezeli, amely nem engedélyezi az írási hozzáférést a példánymezőkhöz (a konstruktorok kivételével).
16.2.3 Ref módosító
A ref
módosító azt jelzi, hogy a struct_declaration deklarál egy típust, amelynek példányai a végrehajtási veremhez vannak lefoglalva. Ezeket a típusokat ref struct típusoknak nevezzük. A ref
módosító kijelenti, hogy a példányok ref-szerű mezőket tartalmazhatnak, és nem másolhatók ki a biztonságos környezetből (16.4.15. §). A refstruktúra biztonságos környezetének meghatározására vonatkozó szabályokat a 16.4.15-ben ismertetjük.
Fordítási idejű hiba, ha az alábbi környezetekben refstruktúratípust használ:
- Tömb elemtípusaként.
- Osztály vagy szerkezet deklarált típusaként, amely nem rendelkezik módosítóval
ref
. - Be van jelölve vagy
System.ValueType
System.Object
be van jelölve. - Típusargumentumként.
- A rekordelem típusaként.
- Aszinkron metódus.
- Egy iterátor.
- Nincs átalakítás típusról
ref struct
típusra vagy típusraobject
System.ValueType
. - Egy
ref struct
típus nem deklarálható interfész implementálásához. - A típusban
object
deklarált vagy abbanSystem.ValueType
deklarált, de felül nem bíráltref struct
példánymetódus nem hívható meg ilyenref struct
típusú fogadóval. - Egy típusú példánymetódus
ref struct
nem rögzíthető a metóduscsoport delegált típusúvá alakításával. - A refstruktúra nem rögzíthető lambda kifejezéssel vagy helyi függvénnyel.
Megjegyzés: Az A
ref struct
nem deklarálhatasync
példánymetódusokat, és nem használhat példánymetóduson belüli utasítástyield return
yield break
, mert az implicitthis
paraméter nem használható ezekben a kontextusokban. végjegyzet
Ezek a korlátozások biztosítják, hogy egy változótípus ref struct
ne hivatkozzon a már nem érvényes veremmemóriára vagy a már nem érvényes változókra.
16.2.4 Részleges módosító
A partial
módosító azt jelzi, hogy ez a struct_declaration részleges típusdeklaráció.
A 15.2.7.
16.2.5 Strukturáló felületek
A szerkezet deklarációja tartalmazhat egy struct_interfaces specifikációt, amely esetben a szerkezet állítólag közvetlenül implementálja az adott interfésztípusokat. Egy strukturált szerkezettípus esetében, beleértve az általános típusdeklarációban deklarált beágyazott típust is (15.3.9.7. §) minden implementált illesztőtípust az adott interfész minden egyes type_parameter helyettesítve a létrehozott típus megfelelő type_argument .
struct_interfaces
: ':' interface_type_list
;
A részleges szerkezet deklaráció több részén (15.2.7. §) található interfészek kezelését a 15.2.4.3.
A felület implementációit a 18.6.
16.2.6 Szerkezettörzs
A szerkezet struct_body határozza meg a szerkezet tagjait.
struct_body
: '{' struct_member_declaration* '}'
;
16.3 Tagok strukturálás
A szerkezet tagjai a struct_member_declarationáltal bevezetett tagokból és a típusból System.ValueType
öröklődő tagokból állnak.
struct_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| operator_declaration
| constructor_declaration
| static_constructor_declaration
| type_declaration
| fixed_size_buffer_declaration // unsafe code support
;
fixed_size_buffer_declaration (23.8.2. §) csak nem biztonságos kódban érhető el (23. §).
Megjegyzés: A finalizer_declaration kivételével a class_member_declaration összes típusa is struct_member_declarations. végjegyzet
A 16.4. §-ban feljegyzett különbségek kivételével a 15.3–15.12. §-ban foglalt osztálytagok leírása a tagokat is érvényes.
16.4 Osztály- és szerkezetkülönbségek
16.4.1 Általános
A szerkezetek számos fontos módon különböznek az osztályoktól:
- A szerkezetek értéktípusok (16.4.2. §).
- Minden struktúratípus implicit módon öröklődik az osztálytól
System.ValueType
(16.4.3. §). - Egy szerkezet típusú változóhoz való hozzárendelés létrehozza a hozzárendelt érték másolatát (16.4.4.4. §).
- A szerkezet alapértelmezett értéke az az érték, amelyet az összes mező alapértelmezett értékre állításával állítanak elő (16.4.5. §).
- A boxing és a unboxing műveletek egy szerkezettípus és bizonyos referenciatípusok közötti konvertálásra szolgálnak (16.4.6. §).
- Az strustruktúra tagjain belül más a jelentésük
this
(16.4.7. §). - A szerkezet példánymező-deklarációi nem tartalmazhatnak változó inicializálókat (16.4.8. §).
- A szerkezet nem deklarálhat paraméter nélküli példánykonstruktort (16.4.9.§).
- A szerkezetek nem deklarálhatnak véglegesítőt.
- Az eseménydeklarációk, a tulajdonságdeklarációk, a tulajdonságkiegészítők, az indexelő deklarációk és a metódusdeklarációk esetében engedélyezett a módosító
readonly
, míg az osztályokban ezeknél a tagtípusoknál ez általánosan nem engedélyezett.
16.4.2 Értékszemantika
A szerkezetek értéktípusok (8.3.§), és azt mondják, hogy érték szemantikával rendelkeznek. Az osztályok viszont referenciatípusok (8.2.§), és azt mondják, hogy referencia szemantikával rendelkeznek.
A szerkezet típusú változók közvetlenül tartalmazzák a szerkezet adatait, míg egy osztálytípus változója az adatokat tartalmazó objektumra mutató hivatkozást tartalmaz. Ha egy struktúra B
egy példány típusú A
mezőt tartalmaz, és A
egy strukturálási típus, akkor fordítási időhiba A
, amely a B
függvénytől függ, vagy egy olyan típus, amelyből B
létrejön. A struct X
közvetlenül attól függ, egy struct Y
, ha X
Y
típusú példánymezőt tartalmaz. A definíció alapján a szerkezetek teljes halmaza, amelytől a szerkezet függ, a közvetlen kapcsolat tranzitív lezárása.
Példa:
struct Node { int data; Node next; // error, Node directly depends on itself }
hiba, mert
Node
egy saját típusú példánymezőt tartalmaz. Egy másik példastruct A { B b; } struct B { C c; } struct C { A a; }
hiba, mert az egyes típusok
A
B
, ésC
egymástól függnek.záró példa
Osztályokkal két változó hivatkozhat ugyanarra az objektumra, és így az egyik változón végzett műveletek hatással lehetnek a másik változó által hivatkozott objektumra. A szerkezetek esetében a változók mindegyike saját adatmásolattal rendelkezik (kivéve a hivatkozási paramétereket), és az egyiken végzett műveletek nem befolyásolhatják a másikat. Továbbá, kivéve, ha explicit módon null értékű (8.3.12. §), a szerkezettípus értékei nem lehetnek null
.
Megjegyzés: Ha egy szerkezet hivatkozástípusú mezőt tartalmaz, akkor a hivatkozott objektum tartalmát más műveletek is módosíthatják. Azonban maga a mező értéke, vagyis az objektum, amelyre hivatkozik, nem módosítható egy másik strukturálási érték mutációja révén. végjegyzet
Példa: Tekintettel a következőkre
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point a = new Point(10, 10); Point b = a; a.x = 100; Console.WriteLine(b.x); } }
a kimenet a következő
10
: . A hozzárendelésa
b
az érték másolatát hozza létre, ésb
így a hozzárendelésa.x
nem érinti. HaPoint
ehelyett osztályként lett deklarálva, a kimenet azért lett100
volna, merta
b
ugyanarra az objektumra hivatkozna.záró példa
16.4.3 Öröklés
Minden struktúratípus implicit módon örököl az osztálytól System.ValueType
, amely viszont az osztálytól object
öröklődik. A szerkezetdeklarációk megadhatják a implementált felületek listáját, de a szerkezetdeklarációk nem adhatnak meg alaposztályt.
A szerkezettípusok soha nem absztraktak, és mindig implicit módon vannak lezárva. A abstract
szerkezetnyilatkozatban ezért a módosítók és sealed
módosítók nem engedélyezettek.
Mivel az öröklés nem támogatott a szerkezetek esetében, a tag deklarált akadálymentessége nem lehet protected
, private protected
vagy protected internal
.
A szerkezetben lévő függvénytagok nem lehetnek absztraktak vagy virtuálisak, és a override
módosító csak az örökölt System.ValueType
metódusokat bírálhatja felül.
16.4.4 Hozzárendelés
Egy szerkezet típusú változóhoz való hozzárendelés létrehozza a hozzárendelt érték másolatát. Ez eltér az osztálytípus változóihoz való hozzárendeléstől, amely a hivatkozást másolja, de a hivatkozás által azonosított objektumot nem.
A hozzárendeléshez hasonlóan, ha egy szerkezetet értékparaméterként ad át, vagy függvénytag eredményeként ad vissza, létrejön a szerkezet egy példánya. A struktúra egy függvénytagra mutató hivatkozással továbbítható egy by-reference paraméter használatával.
Ha egy szerkezet tulajdonsága vagy indexelője egy hozzárendelés célja, a tulajdonsághoz vagy indexelőhöz való hozzáféréshez társított példánykifejezést változóként kell besorolni. Ha a példánykifejezés értékként van besorolva, fordítási időhiba lép fel. Ezt a 12.21.2.
16.4.5 Alapértelmezett értékek
A 9.3. §-ban leírtak szerint számos változó automatikusan inicializálódik az alapértelmezett értékre a létrehozásukkor. Az osztálytípusok és más referenciatípusok változói esetében ez az alapértelmezett érték.null
Mivel azonban a szerkezetek olyan értéktípusok, amelyek nem lehetnek null
, a szerkezetek alapértelmezett értéke az az érték, amelyet az összes értéktípus mező alapértelmezett értékére és az összes referenciatípus-mezőre null
való beállításával állítanak elő.
Példa: A fenti deklarált szerkezetre hivatkozva
Point
a példaPoint[] a = new Point[100];
A tömb minden egyes
Point
elemét inicializálja a létrehozott értékre, és nullára állítja ax
y
mezőket.záró példa
A szerkezet alapértelmezett értéke megegyezik a szerkezet alapértelmezett konstruktorának visszaadott értékével (8.3.3. §). Az osztálytól eltérően a szerkezetek nem deklarálhatnak paraméter nélküli példánykonstruktort. Ehelyett minden szerkezet implicit módon paraméter nélküli példánykonstruktorsal rendelkezik, amely mindig azt az értéket adja vissza, amely az összes mező alapértelmezett értékre állításából ered.
Megjegyzés: A szerkezeteket úgy kell megtervezni, hogy az alapértelmezett inicializálási állapotot érvényes állapotnak tekintsék. A példában
struct KeyValuePair { string key; string value; public KeyValuePair(string key, string value) { if (key == null || value == null) { throw new ArgumentException(); } this.key = key; this.value = value; } }
a felhasználó által definiált példánykonstruktor csak akkor véd az értékek ellen
null
, ha explicit módon hívják meg. Azokban az esetekben, amikor egyKeyValuePair
változó alapértelmezett érték inicializálása történik, a mezők éskey
avalue
mezők leszneknull
, és a szerkezetnek készen kell állnia az állapot kezelésére.végjegyzet
16.4.6 Boxing és unboxing
Egy osztálytípus értéke átalakítható típussá object
vagy interfésztípussá, amelyet az osztály egyszerűen a hivatkozás fordításkor egy másik típusként kezel. Hasonlóképpen, egy típus object
vagy egy interfésztípus értéke a hivatkozás módosítása nélkül is átalakítható osztálytípussá (ebben az esetben természetesen futásidejű típusellenőrzésre van szükség).
Mivel a szerkezetek nem referenciatípusok, ezeket a műveleteket másképpen implementáljuk a szerkezettípusokhoz. Ha egy strukturálási típus értékét átalakítják bizonyos referenciatípusokká (a 10.2.9. §-ban meghatározottak szerint), boxing művelet történik. Hasonlóképpen, ha bizonyos referenciatípusok (a 10.3.7. §-ban meghatározottak szerint) értékét visszaalakítjuk egy strukturálási típusra, a rendszer lezáró műveletet fog végrehajtani. Az osztálytípusok ugyanazon műveleteitől lényeges különbség, hogy a dobozolás és a kicsomagolás átmásolja a strukturálási értéket a dobozos példányba vagy azon kívülre.
Megjegyzés: Így egy boxing vagy unboxing művelet után a beérkezett üzenetek
struct
módosításai nem jelennek meg a dobozosstruct
. végjegyzet
A dobozolással és a dobozolással kapcsolatos további részletekért lásd a 10.2.9 . és a 10.3.7.
16.4.7 Ennek jelentése
this
A szerkezet jelentése eltér az osztály jelentésétől this
a 12.8.14. Ha egy strukturálási típus felülbírál egy virtuális metódust, amely System.ValueType
Equals
a virtuális metódus meghívásától öröklődik GetHashCode
a strukturálási típus egy példányán keresztül, ToString
nem okoz boxolást. Ez akkor is igaz, ha a szerkezet típusparaméterként van használva, és a meghívás a típusparaméter-típus egy példányán keresztül történik.
Példa:
struct Counter { int value; public override string ToString() { value++; return value.ToString(); } } class Program { static void Test<T>() where T : new() { T x = new T(); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); } static void Main() => Test<Counter>(); }
A program kimenete:
1 2 3
Bár ez rossz stílust
ToString
, hogy mellékhatások, a példa azt mutatja, hogy nem történt boxing a három meghívást ax.ToString()
.záró példa
Hasonlóképpen, a boxing soha nem történik implicit módon, amikor egy tagot korlátozott típusparaméteren ér el, amikor a tagot az értéktípuson belül implementálják. Tegyük fel például, hogy egy interfész ICounter
tartalmaz egy metódust Increment
, amely egy érték módosítására használható. Ha ICounter
kényszerként használják, a metódus implementációját a Increment
rendszer a meghívott változóra Increment
való hivatkozással hívja meg, nem pedig dobozos másolattal.
Példa:
interface ICounter { void Increment(); } struct Counter : ICounter { int value; public override string ToString() => value.ToString(); void ICounter.Increment() => value++; } class Program { static void Test<T>() where T : ICounter, new() { T x = new T(); Console.WriteLine(x); x.Increment(); // Modify x Console.WriteLine(x); ((ICounter)x).Increment(); // Modify boxed copy of x Console.WriteLine(x); } static void Main() => Test<Counter>(); }
Az első hívás, amely
Increment
módosítja a változóx
értékét. Ez nem egyezik meg a második hívássalIncrement
, amely módosítja a dobozos másolatx
értékét. Így a program kimenete a következő:0 1 1
záró példa
16.4.8 Mező inicializálók
A 16.4.5. §-ban leírtak szerint a szerkezet alapértelmezett értéke abból áll, hogy az összes értéktípusmezőt az alapértelmezett értékre állítja, és az összes referenciatípusmezőt az alapértelmezett értékre null
állítja. Ezért a szerkezet nem teszi lehetővé a példányok meződeklarációinak változó inicializálóit. Ez a korlátozás csak a példánymezőkre vonatkozik. A szerkezet statikus mezői változó inicializálókat tartalmazhatnak.
Példa: A következő
struct Point { public int x = 1; // Error, initializer not permitted public int y = 1; // Error, initializer not permitted }
hiba történt, mert a példány meződeklarációi változó inicializálókat tartalmaznak.
záró példa
A field_declaration, amely közvetlenül egy struct_declaration belsejében van deklarálva, amely rendelkezik a struct_modifierreadonly
-rel, rendelkeznie kell a field_modifierreadonly
-rel.
16.4.9 Konstruktorok
Az osztálytól eltérően a szerkezetek nem deklarálhatnak paraméter nélküli példánykonstruktort. Ehelyett minden szerkezetnek van egy paraméter nélküli példánykonstruktora, amely mindig azt az értéket adja vissza, amely abból ered, hogy az összes értéktípusmezőt az alapértelmezett értékre állítja, az összes referenciatípus-mezőt pedig a (null
. §) értékre . A szerkezetek deklarálhatják a paraméterekkel rendelkező példánykonstruktorokat.
Példa: Tekintettel a következőkre
struct Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point p1 = new Point(); Point p2 = new Point(0, 0); } }
az utasítások egyaránt nullával rendelkező
Point
ésx
inicializált utasításty
hoznak létre.záró példa
A szerkezetpéldány-konstruktorok nem tartalmazhatnak konstruktor inicializálót az űrlap base(
argument_list)
, ahol a argument_list nem kötelező.
A this
szerkezetpéldány-konstruktor paramétere megfelel a struktúratípus kimeneti paraméterének. Ezért mindenképpen ki kell osztani (this
. §) minden olyan helyen, ahol a konstruktor visszatér. Hasonlóképpen, a konstruktor törzsében nem olvasható (akár implicit módon is), mielőtt biztosan hozzárendelték volna.
Ha a szerkezetpéldány konstruktora konstruktor inicializálót ad meg, akkor az inicializáló ehhez a konstruktor törzse előtt bekövetkező határozott hozzárendelésnek minősül. Ezért maga a törzs nem rendelkezik inicializálási követelményekkel.
Példa: Fontolja meg az alábbi példánykonstruktor-implementációt:
struct Point { int x, y; public int X { set { x = value; } } public int Y { set { y = value; } } public Point(int x, int y) { X = x; // error, this is not yet definitely assigned Y = y; // error, this is not yet definitely assigned } }
Egyetlen példányfüggvény-tag sem hívható meg (beleértve a tulajdonságokhoz
X
ésY
a készlethez tartozó tartozékokat is) mindaddig, amíg a felépítendő szerkezet összes mezője biztosan ki nem van rendelve. Vegye figyelembe azonban, hogy haPoint
a szerkezet helyett osztály lenne, akkor a példánykonstruktor implementációja engedélyezve lenne. Ez alól egyetlen kivétel van, amely automatikusan implementált tulajdonságokat tartalmaz (15.7.4. §). A határozott hozzárendelési szabályok (12.21.2. §) kifejezetten mentesítik az adott szerkezettípus egy példánykonstruktorán belüli autotulajdonságra való hozzárendelést: az ilyen hozzárendelés az automatikus tulajdonság rejtett háttérmezőjének határozott hozzárendelése. Így a következők engedélyezettek:struct Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; // allowed, definitely assigns backing field Y = y; // allowed, definitely assigns backing field } }
záró példa]
16.4.10 Statikus konstruktorok
A szerkezetek statikus konstruktorai ugyanazokat a szabályokat követik, mint az osztályok esetében. A szerkezettípus statikus konstruktorának végrehajtását az alábbi események közül az első aktiválja, amely egy alkalmazástartományon belül következik be:
- A szerkezettípus statikus tagjára hivatkozunk.
- A szerkezettípus explicit módon deklarált konstruktorát hívjuk meg.
Megjegyzés: A szerkezettípusok alapértelmezett értékeinek (16.4.5.§) létrehozása nem aktiválja a statikus konstruktort. (Erre példa egy tömb elemeinek kezdeti értéke.) végjegyzet
16.4.11 Tulajdonságok
A property_declaration (§15.7.1) egy struct_declaration példánytulajdonság esetén tartalmazhatja a property_modifierreadonly
. A statikus tulajdonság azonban nem tartalmazhat ilyen módosító tulajdonságot.
Fordítási idejű hiba, ha egy példány-struktúra-változó állapotát próbáljuk módosítani ennek a struktúrának egy csak olvasható tulajdonságán keresztül.
Fordítási hibát okoz, ha egy automatikusan implementált tulajdonság readonly
módosítóval rendelkezik, és egy set
metódussal is.
Fordítási idejű hiba, ha egy readonly
szerkezet automatikusan implementált tulajdonsága rendelkezik set
hozzáférővel.
A szerkezeten belül readonly
deklarált automatikusan implementált tulajdonságnak nem kell módosítóval rendelkeznie readonly
, mivel a get
tartozék implicit módon feltételezi, hogy olvasható.
Fordítási idejű hiba, ha egy readonly
módosító szerepel magán a tulajdonságon, valamint annak get
vagy set
hozzáférőin.
Fordítási idejű hiba, ha egy tulajdonság minden hozzáférőjén readonly módosító van.
Megjegyzés: A hiba kijavításához helyezze át a módosítót az accessor-okból a tulajdonságba. végjegyzet
Az automatikusan implementált tulajdonságok (§15.7.4) rejtett háttérmezőket használnak, amelyek csak a tulajdonság tartozékai számára érhetők el.
Megjegyzés: Ez a hozzáférési korlátozás azt jelenti, hogy az automatikusan implementált tulajdonságokat tartalmazó szerkezetek konstruktorainak gyakran explicit konstruktor-inicializálóra van szükségük, ahol egyébként nincs szükségük rá, hogy kielégítsék a függvénytagok meghívása vagy a konstruktor visszatérése előtt határozottan hozzárendelt összes mező követelményét. végjegyzet
16.4.12 Módszerek
A struct_declaration példánymetódusra vonatkozó method_declaration (15.6.1. §) tartalmazhatja a method_modifier. A statikus módszer azonban nem tartalmazhat ilyen módosító elemet.
Fordítási idejű hiba egy példánystruktúra állapotának módosítási kísérlete egy csak olvasható metódussal, amely az adott struktúrában van deklarálva.
Bár egy írásvédett metódus meghívhat egy testvér, nem írásvédett metódust, tulajdonság vagy indexelő lekérdező hozzáférőt, ez implicit másolat létrehozását eredményezi a this
számára, mint védelmi intézkedést.
Az csak olvasható metódus meghívhat egy testvértulajdonságot vagy indexelő beállítót, amely csak olvasható. Ha egy testvértag kiegészítője nem explicit vagy implicit módon olvasható, fordítási hiba történik.
Egy részleges method_declaration metódusok mindegyike rendelkezik readonly
módosítóval, vagy egyik sem rendelkezik.
16.4.13 Indexelők
Egy indexer_declaration (§15.9) példányindexelő egy struct_declaration-ban tartalmazhat indexer_modifierreadonly
.
Fordítási időbeli hiba keletkezik, ha megpróbáljuk módosítani egy példánystruktúra változó állapotát az adott struktúrában deklarált, csak olvasható indexelőn keresztül.
Fordítási idejű hiba, ha egy readonly
módosító található magán az indexelőn, vagy bármelyik get
vagy set
hozzáférőjén.
Az indexelő minden hozzáférőjén csak olvasható módosító esetén fordítási idejű hiba lép fel.
Megjegyzés: A hiba kijavításához helyezze át a módosítót a tartozékból az indexelőbe. végjegyzet
16.4.14 Események
Egy event_declaration (15.8.1. §), amely egy példányban lévő, nem mezőszerű eseményhez tartozik egy struct_declaration-ban, tartalmazhatja a event_modifierreadonly
. A statikus esemény azonban nem tartalmazhat ilyen módosító elemet.
16.4.15 Biztonságos környezet korlátozása
16.4.15.1 Általános
Fordításkor minden kifejezés egy olyan környezethez van társítva, amelyben az adott példány és az összes mező biztonságosan elérhető, a biztonságos környezete. A biztonságos környezet egy olyan környezet, amely egy kifejezést foglal magában, amely biztonságos ahhoz, hogy az érték megmenekülhessen.
Minden olyan kifejezés, amelynek fordítási ideje nem refstruktúra, a hívókörnyezet biztonságos kontextusával rendelkezik.
Egy default
kifejezés bármilyen típushoz rendelkezik a hívókörnyezet biztonságos környezetével.
Minden olyan nem alapértelmezett kifejezés esetében, amelynek fordítási ideje refstruktúra, az alábbi szakaszokban meghatározott biztonságos környezettel rendelkezik.
A biztonságos környezet rögzíti, hogy egy érték mely környezetbe másolható. Ha egy biztonságos környezettel rendelkező kifejezéstől E1
egy biztonságos környezettel S1
E2
rendelkező kifejezéshez S2
hozzárendelést ad, az hiba, ha S2
szélesebb kontextusban van, mint S1
.
A referenciaváltozókhoz (9.7.2.§) definiált ref-safe-context értékeknek három különböző biztonságos környezeti értéke van: deklarációblokk, függvénytag és hívókörnyezet. A kifejezések biztonságos környezete a következőképpen korlátozza a használatát:
- A visszautalási nyilatkozat
return e1
esetében a hívó kontextusnake1
kell lennie. - A hozzárendelés
e1 = e2
esetében a biztonságos kontextusnake2
legalább olyan szélesnek kell lennie, mint a biztonságos kontextusnake1
.
Olyan metódushívás esetén, ha van egy ref
típus vagy out
argumentum ref struct
(beleértve a fogadót is, kivéve, ha a típus readonly
), a biztonságos környezettel S1
együtt, akkor egyetlen argumentumnak (beleértve a fogadót is) lehet szűkebb biztonságos környezete, mint S1
.
16.4.15.2 Biztonságos paraméterkörnyezet
Egy refstruktúratípus paramétere, beleértve a this
példánymetódus paraméterét is, a hívókörnyezet biztonságos kontextusával rendelkezik.
16.4.15.3 Helyi változók biztonságos környezete
A ref struct típusú helyi változók biztonságos környezettel rendelkeznek az alábbiak szerint:
- Ha a változó egy
foreach
ciklus iterációs változója, akkor a változó biztonságos környezete megegyezik aforeach
hurok kifejezésének biztonságos kontextusával. - Ellenkező esetben, ha a változó deklarációja inicializálóval rendelkezik, akkor a változó biztonságos környezete megegyezik az inicializáló biztonságos környezetével.
- Ellenkező esetben a változó nem inicializálódik a deklarálási ponton, és a hívókörnyezet biztonságos kontextusával rendelkezik.
16.4.15.4 A mező biztonságos környezete
Egy olyan mezőre e.F
mutató hivatkozás, amelynek típusa F
egy ref struct típus, egy olyan biztonságos környezettel rendelkezik, amely megegyezik a biztonságos környezetével e
.
16.4.15.5 Operátorok
A felhasználó által definiált operátor alkalmazását metódushívásként kezeli a rendszer (16.4.15.6. §).
Az olyan operátorok esetében, amelyek értéket adnak, például e1 + e2
vagy c ? e1 : e2
, az eredmény biztonságos kontextusa a legszűkebb környezet az operátor operandusainak biztonságos környezetei között. Ennek következtében egy olyan nemáris operátor esetében, amely értéket ad, például +e
az eredmény biztonságos kontextusa az operandus biztonságos kontextusa.
Megjegyzés: A feltételes operátor első operandusa egy
bool
, így a biztonságos környezete a hívó-környezet. Ebből következik, hogy az eredményül kapott biztonságos környezet a második és harmadik operandus legszűkebb biztonságos kontextusa. végjegyzet
16.4.15.6 Metódus és tulajdonsághívás
Egy metódushívásból e1.M(e2, ...)
vagy tulajdonsághívásból e.P
eredő érték a legkisebb környezettel rendelkezik biztonságos környezettel:
- hívókörnyezet.
- Az összes argumentumkifejezés (beleértve a fogadót is) biztonságos környezete.
A tulajdonsághívást (vagy get
set
) a fenti szabályok az alapul szolgáló metódus meghívásának metódusaként kezelik.
16.4.15.7 stackalloc
A stackalloc-kifejezés eredménye a függvénytag biztonságos kontextusával rendelkezik.
16.4.15.8 Konstruktor-meghívások
A new
konstruktort meghívó kifejezés ugyanazokat a szabályokat követi, mint egy metódushívás, amely úgy tekinthető, hogy a létrehozott típust adja vissza.
Emellett a biztonságos környezet a legkisebb az összes objektum inicializáló kifejezés argumentumainak és operandusainak biztonságos környezetei közül, rekurzív módon, ha van inicializáló.
Megjegyzés: Ezek a szabályok arra támaszkodnak
Span<T>
, hogy nem rendelkezik konstruktorsal az alábbi űrlapon:public Span<T>(ref T p)
Az ilyen konstruktorok a mezőként használt példányokat
Span<T>
megkülönböztethetetlenekké teszik egyref
mezőből. A dokumentumban leírt biztonsági szabályok attól függenek,ref
hogy a mezők nem érvényesek a C# vagy a .NET-ben. végjegyzet
ECMA C# draft specification