Megosztás a következőn keresztül:


16 Szerkezetek

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 inta , 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.

readonlyA 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 readonlykell .
  • 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.ValueTypeSystem.Objectbe 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ípusra objectSystem.ValueType.
  • Egy ref struct típus nem deklarálható interfész implementálásához.
  • A típusban object deklarált vagy abban System.ValueType deklarált, de felül nem bírált ref struct példánymetódus nem hívható meg ilyen ref 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álhat async példánymetódusokat, és nem használhat példánymetóduson belüli utasítást yield returnyield break , mert az implicit this 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 Blétrejön. A struct Xközvetlenül attól függ, egy struct Y, ha XYtí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élda

struct A { B b; }
struct B { C c; }
struct C { A a; }

hiba, mert az egyes típusokAB, és C 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és ab az érték másolatát hozza létre, és b így a hozzárendelés a.xnem érinti. Ha Point ehelyett osztályként lett deklarálva, a kimenet azért lett 100 volna, mert ab 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 protectedvagy 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.ValueTypemetó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 nullvaló beállításával állítanak elő.

Példa: A fenti deklarált szerkezetre hivatkozva Point a példa

Point[] a = new Point[100];

A tömb minden egyes Point elemét inicializálja a létrehozott értékre, és nullára állítja a xy 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 egy KeyValuePair változó alapértelmezett érték inicializálása történik, a mezők és key a value 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 dobozos struct. 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.ValueTypeEqualsa 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, ToStringnem 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 a x.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ással Increment, amely módosítja a dobozos másolat xé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 és x inicializált utasítást y 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 és Ya 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 ha Point 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 S1E2rendelkező 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 e1esetében a hívó kontextusnak e1 kell lennie.
  • A hozzárendelés e1 = e2 esetében a biztonságos kontextusnak e2 legalább olyan szélesnek kell lennie, mint a biztonságos kontextusnak e1.

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 S1együ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 a foreach 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.Fmutató 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 +eaz 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 getset) 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 egy ref 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