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


9 Változók

9.1 Általános

A változók a tárolási helyeket jelölik. Minden változónak van egy típusa, amely meghatározza, hogy milyen értékek tárolhatók a változóban. A C# egy típusbiztos nyelv, a C# fordító pedig garantálja, hogy a változókban tárolt értékek mindig a megfelelő típusúak legyenek. A változó értéke a hozzárendeléssel vagy az ++ operátorok -- használatával módosítható.

A változót mindenképpen ki kell osztani (9.4. §) az értékének megszerzése előtt.

A következő alklámokban leírtak szerint a változók kezdetben hozzárendelve vagy kezdetben nem lesznek hozzárendelve. Az eredetileg hozzárendelt változóknak van egy jól definiált kezdeti értéke, és mindig határozottan hozzárendeltnek számítanak. Az eredetileg nem hozzárendelt változóknak nincs kezdeti értéke. Ahhoz, hogy egy eredetileg hozzárendeletlen változót biztosan hozzárendeltnek lehessen tekinteni egy adott helyen, a változóhoz való hozzárendelésnek minden lehetséges végrehajtási útvonalon meg kell történnie, amely az adott helyre vezet.

9.2 Változókategóriák

9.2.1 Általános

A C# nyolc változókategóriát határoz meg: statikus változókat, példányváltozókat, tömbelemeket, értékparamétereket, bemeneti paramétereket, referenciaparamétereket, kimeneti paramétereket és helyi változókat. Az alábbi alklámok ezen kategóriák mindegyikét ismertetik.

Példa: Az alábbi kódban

class A
{
    public static int x;
    int y;

    void F(int[] v, int a, ref int b, out int c, in int d)
    {
        int i = 1;
        c = a + b++ + d;
    }
}

x statikus változó, y példányváltozó, v[0] tömbelem, a értékparaméter, b referenciaparaméter, c kimeneti paraméter, d bemeneti paraméter, helyi i változó. záró példa

9.2.2 Statikus változók

A módosítóval static deklarált mező statikus változó. A statikus változó a konstruktor (static.§) végrehajtása előtt jön létre, és a kapcsolódó alkalmazástartomány megszűnésekor megszűnik.

A statikus változó kezdeti értéke a változó típusának alapértelmezett értéke (9.3. §).

A végleges hozzárendelés ellenőrzése céljából egy statikus változót először hozzárendeltnek tekintünk.

9.2.3 Példányváltozók

9.2.3.1 Általános

A módosító nélkül static deklarált mező egy példányváltozó.

9.2.3.2 Példányváltozók osztályokban

Egy osztály példányváltozója akkor jön létre, amikor létrejön az adott osztály új példánya, és megszűnik, ha nincs hivatkozás az adott példányra, és a példány véglegesítője (ha van ilyen) végrehajtva.

Egy osztály példányváltozójának kezdeti értéke a változó típusának alapértelmezett értéke (9.3. §).

A határozott hozzárendelés ellenőrzése céljából az osztály példányváltozóját kezdetben hozzárendeltnek tekintjük.

9.2.3.3 Példányváltozók a szerkezetekben

Egy szerkezet példányváltozójának élettartama pontosan megegyezik azzal a szerkezetváltozóval, amelyhez tartozik. Más szóval, ha egy strukturált típusú változó létrejön vagy megszűnik, akkor a szerkezet példányváltozói is.

A szerkezet példányváltozójának kezdeti hozzárendelési állapota megegyezik az azt tartalmazó struct változó állapotával. Más szóval, ha egy szerkezetváltozót kezdetben hozzárendeltnek tekintenek, akkor a példányváltozók is, és ha egy strukturált változót eredetileg nem hozzárendeltnek tekintenek, a példányváltozók hasonlóképpen nem lesznek hozzárendelve.

9.2.4 Tömbelemek

A tömb elemei egy tömbpéldány létrehozásakor jönnek létre, és megszűnnek, ha nincs hivatkozás az adott tömbpéldányra.

A tömb egyes elemeinek kezdeti értéke a tömbelemek típusának alapértelmezett értéke (9.3. §).

A végleges hozzárendelés ellenőrzése céljából a tömbelem kezdetben hozzárendeltnek minősül.

9.2.5 Értékparaméterek

Az értékparaméter a függvénytag (metódus, példánykonstruktor, tartozék vagy operátor) vagy névtelen függvény meghívásával jön létre, amelyhez a paraméter tartozik, és inicializálva lesz a meghívásban megadott argumentum értékével. Az értékparaméter általában megszűnik, amikor a függvény törzsének végrehajtása befejeződik. Ha azonban az értékparamétert egy névtelen függvény rögzíti (12.19.6.2. §), az élettartama legalább addig tart, amíg a névtelen függvényből létrehozott delegált vagy kifejezésfa jogosult a szemétgyűjtésre.

A határozott hozzárendelés ellenőrzése céljából egy értékparamétert elsőként hozzárendeltnek tekintünk.

Az értékparamétereket a 15.6.2.2.

9.2.6 Referenciaparaméterek

A referenciaparaméter egy referenciaváltozó (§9.7), amely a függvény tagjának, delegáltjának, névtelen függvényének vagy helyi függvényének meghívása után jön létre, és annak hivatkozását inicializálja a meghívás argumentumaként megadott változóra. A függvény törzsének végrehajtása után megszűnik a referenciaparaméter. Az értékparaméterekkel ellentétben a referenciaparaméter nem rögzíthető (9.7.2.9. §).

A referenciaparaméterekre az alábbi határozott hozzárendelési szabályok vonatkoznak.

Megjegyzés: A kimeneti paraméterekre vonatkozó szabályok eltérőek, és azokat a (9.2.7. §)-ban ismertetjük. végjegyzet

  • A változót mindenképpen hozzárendelni kell (9.4. §), mielőtt referenciaparaméterként átadható egy függvénytagban vagy meghatalmazotti meghívásban.
  • Egy függvénytagon vagy névtelen függvényen belül a rendszer először hozzárendeltnek tekint egy referenciaparamétert.

A referenciaparamétereket a 15.6.2.3.3.

9.2.7 Kimeneti paraméterek

A kimeneti paraméter egy referenciaváltozó (§9.7), amely a függvény tagjának, delegáltjának, névtelen függvényének vagy helyi függvényének meghívása után jön létre, és annak hivatkozását inicializálja a meghívás argumentumaként megadott változóra. A kimeneti paraméter megszűnik, amikor a függvény törzsének végrehajtása befejeződik. Az értékparaméterekkel ellentétben a kimeneti paraméter nem rögzíthető (9.7.2.9. §).

A kimeneti paraméterekre az alábbi határozott hozzárendelési szabályok vonatkoznak.

Megjegyzés: A referenciaparaméterekre vonatkozó szabályok eltérőek, és azokat a (9.2.6. §) ismerteti. végjegyzet

  • A változót nem kell feltétlenül hozzárendelni ahhoz, hogy kimeneti paraméterként átadható legyen egy függvénytagban vagy delegált meghívásban.
  • A függvénytagok vagy delegáltak meghívásának normál befejezését követően a kimeneti paraméterként átadott változók az adott végrehajtási útvonalon lesznek hozzárendelve.
  • Egy függvénytagon vagy névtelen függvényen belül a kimeneti paraméter kezdetben nincs hozzárendelve.
  • A függvénytagok, névtelen függvények vagy helyi függvények minden kimeneti paraméterét határozottan hozzárendelni kell (9.4. §), mielőtt a függvénytag, a névtelen függvény vagy a helyi függvény normálisan visszatér.

A kimeneti paramétereket a 15.6.2.3.4.

9.2.8 Bemeneti paraméterek

A bemeneti paraméter egy referenciaváltozó (§9.7), amely a függvény tagjának, delegáltjának, névtelen függvényének vagy helyi függvényének meghívásakor jön létre, és annak hivatkozását inicializálja a meghívás argumentumaként megadott variable_reference . A függvény törzsének végrehajtása után megszűnik egy bemeneti paraméter. Az értékparaméterekkel ellentétben a bemeneti paraméter nem rögzíthető (9.7.2.9. §).

A bemeneti paraméterekre az alábbi határozott hozzárendelési szabályok vonatkoznak.

  • A változót mindenképpen hozzárendelni kell (9.4. §), mielőtt bemeneti paraméterként átadható egy függvénytagban vagy meghatalmazotti meghívásban.
  • Egy függvénytagon, névtelen függvényen vagy helyi függvényen belül a bemeneti paraméter kezdetben hozzárendeltnek minősül.

A bemeneti paramétereket a 15.6.2.3.2.

9.2.9 Helyi változók

9.2.9.1 Általános

A helyi változókategy try_statement local_variable_declaration, declaration_expression, foreach_statement vagy specific_catch_clausedeklarálja. A helyi változók deklarálhatók bizonyos típusú mintákkal is (11. §). Egy foreach_statement esetében a helyi változó egy iterációs változó (13.9.5. §). Egy specific_catch_clause esetében a helyi változó kivételváltozó (13.11. §). Egy foreach_statement vagy specific_catch_clause által deklarált helyi változó kezdetben hozzárendeltnek minősül.

A local_variable_declaration blokkokban, for_statement, switch_block vagy using_statement fordulhatnak elő. A declaration_expression argument_value, tuple_element pedig dekonstruáló feladat céljaként (out12.21.2. §).

A helyi változó élettartama a program végrehajtásának az a része, amelynek során a tárterület garantáltan lefoglalva lesz. Ez az élettartam a hatókörbe való belépéstől, amelyhez társítva van, legalább addig tart, amíg a hatókör végrehajtása valamilyen módon véget nem ér. (Egy zárt blokk beírása, metódus meghívása vagy egy iterátorblokkból származó érték megadása felfüggeszti, de nem fejeződik be az aktuális hatókör végrehajtásával.) Ha a helyi változót névtelen függvény rögzíti (§12.19.6.2), az élettartama legalább addig tart, amíg a névtelen függvényből létrehozott delegált vagy kifejezésfa, valamint a rögzített változóra hivatkozó egyéb objektumok nem jogosultak szemétgyűjtésre. Ha a szülő hatókör rekurzív vagy iteratív módon van megadva, a rendszer minden alkalommal létrehoz egy új helyi változópéldányt, és minden alkalommal kiértékeli annak inicializálóját.

Megjegyzés: A rendszer minden alkalommal példányosít egy helyi változót, amikor be van írva a hatóköre. Ez a viselkedés a névtelen metódusokat tartalmazó felhasználói kódban látható. végjegyzet

Megjegyzés: Az foreach_statement által deklarált iterációs változó (13.9.5. §) élettartama az adott utasítás egyetlen iterációja. Minden iteráció létrehoz egy új változót. végjegyzet

Megjegyzés: Egy helyi változó tényleges élettartama implementációfüggő. Egy fordító például statikusan megállapíthatja, hogy egy blokk helyi változója csak a blokk egy kis részére használható. Ezzel az elemzéssel a fordító olyan kódot hozhat létre, amely a változó tárolójának rövidebb élettartamát eredményezi, mint a blokk.

A helyi referenciaváltozó által hivatkozott tárolót a rendszer a helyi referenciaváltozó élettartamától függetlenül visszanyeri (7.9. §).

végjegyzet

A local_variable_declaration vagy declaration_expression által bevezetett helyi változók nem inicializálódnak automatikusan, így nincs alapértelmezett érték. Az ilyen helyi változók kezdetben nem hozzárendeltnek minősülnek.

Megjegyzés: Az inicializálót tartalmazó local_variable_declaration kezdetben még nincs hozzárendelve. A deklaráció végrehajtása pontosan úgy viselkedik, mint a változó hozzárendelése (9.4.4.5. §). Változó használata az inicializáló végrehajtása előtt; például az inicializáló kifejezésen belül, vagy az inicializálót megkerülő goto_statement használatával; fordítási időhiba:

goto L;

int x = 1; // never executed

L: x += 1; // error: x not definitely assigned

A helyi változó hatókörén belül fordítási idejű hiba az adott helyi változóra hivatkozni a deklarátort megelőző szöveges pozícióban.

végjegyzet

9.2.9.2 Elvetések

Az elvetés egy helyi változó, amelynek nincs neve. A visszavetést egy deklarációs kifejezés (12.17. §) adhatja meg az azonosítóval _; és implicit módon gépelt (_ vagy var _) vagy explicit módon (T _).

Megjegyzés: _ a deklarációk számos formájában érvényes azonosító. végjegyzet

Mivel egy elvetésnek nincs neve, az egyetlen hivatkozás az általa képviselt változóra az azt tartalmazó kifejezés.

Megjegyzés: Az elvetés azonban átadható kimeneti argumentumként, így a megfelelő kimeneti paraméter a társított tárolási helyet jelöli. végjegyzet

A rendszer először nem rendel hozzá elvetést, ezért az érték elérése mindig hiba.

Példa:

_ = "Hello".Length;
(int, int, int) M(out int i1, out int i2, out int i3) { ... }
(int _, var _, _) = M(out int _, out var _, out _);

A példa feltételezi, hogy nincs deklaráció a névről _ a hatókörben.

A hozzárendelés _ egy egyszerű mintát jelenít meg egy kifejezés eredményének figyelmen kívül hagyásához. A hívás M megjeleníti az elvetések különböző formáit, amely elérhető a halmazokban és a kimeneti paraméterekben.

záró példa

9.3 Alapértelmezett értékek

A változók következő kategóriái automatikusan inicializálódnak az alapértelmezett értékükre:

  • Statikus változók.
  • Osztálypéldányok példányváltozói.
  • Tömbelemek.

A változó alapértelmezett értéke a változó típusától függ, és a következőképpen van meghatározva:

  • Egy value_type változó esetében az alapértelmezett érték megegyezik a value_type alapértelmezett konstruktorával kiszámított értékkel (8.3.3. §).
  • Egy reference_type változó esetében az alapértelmezett érték a .null

Megjegyzés: Az alapértelmezett értékekre való inicializálás általában úgy történik, hogy a memóriakezelő vagy a szemétgyűjtő inicializálja a memóriát az all-bit-zero értékre, mielőtt használathoz rendeli. Ezért célszerű az all-bits-zero használatával a nullhivatkozást jelölni. végjegyzet

9.4 Határozott hozzárendelés

9.4.1 Általános

A függvénytagok vagy névtelen függvények végrehajtható kódjának adott helyén a rendszer azt mondja, hogy egy változót biztosan hozzárendelni, ha egy fordító egy adott statikus folyamatelemzéssel (§9.4.4) bizonyítani tudja, hogy a változó automatikusan inicializálva lett, vagy legalább egy hozzárendelés célja volt.

Megjegyzés: Informálisan kimondva, a határozott hozzárendelés szabályai a következők:

  • Az eredetileg hozzárendelt változót (9.4.2. §) mindig határozottan hozzárendeltnek kell tekinteni.
  • Az eredetileg nem hozzárendelt változót (9.4.3. §) egy adott helyen határozottan hozzárendeltnek kell tekinteni, ha az adott helyre vezető összes lehetséges végrehajtási útvonal legalább az alábbiak egyikét tartalmazza:
    • Egy egyszerű hozzárendelés (12.21.2. §), amelyben a változó a bal operandus.
    • Olyan meghívási kifejezés (§12.8.10) vagy objektumlétrehozási kifejezés (§12.8.17.2), amely kimeneti paraméterként adja át a változót.
    • Helyi változó esetén a változó helyi változódeklarációja (13.6.2. §), amely tartalmaz egy változó inicializálóját.

A fenti informális szabályok alapjául szolgáló formális specifikációt a 9.4.2., a 9.4.3. és a 9.4.4.

végjegyzet

A struct_type változók példányváltozóinak határozott hozzárendelési állapotai egyenként és együttesen is nyomon követhetők. A 9.4.2., a 9.4.3. és a 9.4.4. cikkben leírt szabályokon kívül a következő szabályok vonatkoznak struct_type változókra és azok példányváltozóira:

  • A példányváltozó akkor tekinthető egyértelműen hozzárendeltnek, ha a struct_type változót tartalmazó változót határozottan hozzárendeltnek tekintik.
  • A struct_type változók akkor tekinthetők egyértelműen hozzárendeltnek, ha az egyes példányváltozók egyértelműen hozzárendeltnek minősülnek.

A határozott hozzárendelés a következő környezetekben követelmény:

  • A változót minden olyan helyen ki kell osztani, ahol az értéket megkapják.

    Megjegyzés: Ez biztosítja, hogy a nem definiált értékek soha ne fordulnak elő. végjegyzet

    A változó kifejezésben való előfordulását úgy kell tekinteni, hogy a változó értékét szerzi be, kivéve, ha

    • a változó egy egyszerű feladat bal operandusa,
    • a változó kimeneti paraméterként van átadva, vagy
    • a változó egy struct_type változó, és egy taghozzáférés bal operandusaként fordul elő.
  • Minden olyan helyen, ahol referenciaparaméterként továbbítják, mindenképpen ki kell osztani egy változót.

    Megjegyzés: Ez biztosítja, hogy a meghívandó függvénytag figyelembe vegye az eredetileg hozzárendelt referenciaparamétert. végjegyzet

  • Minden olyan helyen, ahol bemeneti paraméterként továbbítják, mindenképpen ki kell osztani egy változót.

    Megjegyzés: Ez biztosítja, hogy a meghívandó függvénytag figyelembe vegye az eredetileg hozzárendelt bemeneti paramétert. végjegyzet

  • A függvénytag összes kimeneti paraméterét minden olyan helyen ki kell osztani, ahol a függvénytag visszatér (egy visszatérési utasítással vagy a függvénytag törzsének végéig elért végrehajtással).

    Megjegyzés: Ez biztosítja, hogy a függvénytagok ne adjanak vissza nem definiált értékeket a kimeneti paraméterekben, így lehetővé teszi a fordító számára, hogy olyan függvénytag-meghívást vegyenek figyelembe, amely egy változót a változóhoz való hozzárendeléssel egyenértékű kimeneti paraméterként vesz fel. végjegyzet

  • A this struct_type példánykonstruktor változóját minden olyan helyen ki kell osztani, ahol a példánykonstruktor visszatér.

9.4.2 Eredetileg hozzárendelt változók

A változók következő kategóriái először hozzárendeltként vannak besorolva:

  • Statikus változók.
  • Osztálypéldányok példányváltozói.
  • Az eredetileg hozzárendelt szerkezetváltozók példányváltozói.
  • Tömbelemek.
  • Értékparaméterek.
  • Referenciaparaméterek.
  • Bemeneti paraméterek.
  • Záradékban vagy catch utasításban foreach deklarált változók.

9.4.3 Kezdetben nem hozzárendelt változók

A változók alábbi kategóriái kezdetben nem hozzárendeltként vannak besorolva:

  • Az eredetileg nem hozzárendelt strukturált változók példányváltozói.
  • Kimeneti paraméterek, beleértve a this szerkezetpéldány-konstruktorok konstruktor-inicializáló nélküli változóját.
  • Helyi változók, kivéve a záradékban vagy catch utasításban foreach deklaráltakat.

9.4.4 A határozott hozzárendelés meghatározásának pontos szabályai

9.4.4.1 Általános

Annak megállapításához, hogy az egyes használt változók egyértelműen hozzárendelve vannak-e, a fordítónak olyan folyamatot kell használnia, amely megegyezik az ebben az alklámban leírt eljárással.

A függvénytag törzse deklarálhat egy vagy több kezdetben nem hozzárendelt változót. Minden eredetileg nem hozzárendelt vváltozóra vonatkozóan a fordítónak a függvénytag alábbi pontjain meg kell határoznia a vvégleges hozzárendelési állapotot.

  • Az egyes utasítások elején
  • Minden utasítás végén (13.2. §)
  • Minden olyan íven, amely a vezérlést egy másik utasításba vagy egy utasítás végpontjára továbbítja
  • Az egyes kifejezések elején
  • Az egyes kifejezések végén

A v végleges hozzárendelési állapota a következő lehet:

  • Határozottan hozzárendelve. Ez azt jelzi, hogy az ehhez a ponthoz tartozó összes lehetséges vezérlőfolyamaton a v érték van hozzárendelve.
  • Nem biztos, hogy hozzárendelték. Egy változónak egy típuskifejezés boolvégén lévő állapota esetén a nem feltétlenül hozzárendelt változó állapota az alábbi alállapotok egyikébe eshet (de nem feltétlenül):
    • A valódi kifejezés után egyértelműen hozzárendelve. Ez az állapot azt jelzi, hogy a v egyértelműen ki van rendelve, ha a logikai kifejezés igazként van kiértékelve, de nem feltétlenül van hozzárendelve, ha a logikai kifejezés hamisként van kiértékelve.
    • A hamis kifejezés után egyértelműen hozzárendelve. Ez az állapot azt jelzi, hogy a v akkor van hozzárendelve, ha a logikai kifejezés hamisként van kiértékelve, de nem feltétlenül van hozzárendelve, ha a logikai kifejezés igazként van kiértékelve.

Az alábbi szabályok szabályozzák, hogy az egyes helyeken hogyan határozható meg egy v változó állapota.

9.4.4.2 Az utasítások általános szabályai

  • a v nem feltétlenül van hozzárendelve egy függvénytag törzsének elején.
  • A v végleges hozzárendelési állapotát bármely más utasítás elején a v végleges hozzárendelési állapotának ellenőrzésével határozzuk meg az összes olyan vezérlőfolyamat-átvitelen, amely az adott utasítás kezdetét célozza. Ha (és csak akkor), ha a v minden ilyen vezérlési folyamat átviteléhez biztosan hozzá van rendelve, akkor a v az utasítás elején van hozzárendelve. A lehetséges vezérlőfolyamat-átvitelek halmaza ugyanúgy van meghatározva, mint az ellenőrzőutasítások elérhetősége (13.2. §).
  • A v végleges hozzárendelési állapotát az a , , , blockcheckeduncheckedifwhiledoforforeachvagy lock utasítás végpontján usinghatározza meg, ha ellenőrzi a vswitchállapotát az összes olyan vezérlőfolyamat-átvitelen, amely az adott utasítás végpontját célozza. Ha a v minden ilyen vezérlőfolyamat-átvitelhez hozzá van rendelve, akkor a v egyértelműen az utasítás végén van hozzárendelve. Ellenkező esetben a v nincs egyértelműen hozzárendelve az utasítás végén. A lehetséges vezérlőfolyamat-átvitelek halmaza ugyanúgy van meghatározva, mint az ellenőrzőutasítások elérhetősége (13.2. §).

Megjegyzés: Mivel egy nem elérhető utasításhoz nincsenek vezérlőútvonalak, a v minden bizonnyal a nem elérhető utasítások elején van hozzárendelve. végjegyzet

9.4.4.3 Utasítások blokkolása, ellenőrzött és nem ellenőrzött utasítások

A blokkban lévő utasításlista első utasítására (vagy ha az utasításlista üres, akkor a blokk végpontjára, ha az utasításlista üres) a vezérlőelemen lévő v végleges hozzárendelési állapota megegyezik a blokk előtti v végleges hozzárendelési utasításával, checkedvagy unchecked az utasítással.

9.4.4.4 Kifejezési utasítások

Kifejezési utasítás stmt értéke, amely az expr kifejezésből áll:

  • a v a kitevő elején ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint az stmt elején.
  • Ha v, ha az expr végén egyértelműen ki van rendelve, akkor az egyértelműen az stmt végpontján van hozzárendelve, ellenkező esetben nem az stmt végpontján van hozzárendelve.

9.4.4.5 Nyilatkozatok

  • Ha az stmt inicializálók nélküli deklarációs utasítás, akkor a v az stmt végpontján ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint az stmt elején.
  • Ha az stmt inicializálókkal rendelkező deklarációs utasítás, akkor a v végleges hozzárendelési állapota úgy lesz meghatározva, mintha az stmt utasításlista volna, és mindegyik deklarációhoz egy hozzárendelési utasítás tartozik egy inicializálóval (a deklaráció sorrendjében).

9.4.4.6 Ha utasítás

Az űrlap utasítása:

if ( «expr» ) «then_stmt» else «else_stmt»
  • a v a kitevő elején ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint az stmt elején.
  • Ha a v az expr végén van hozzárendelve, akkor a vezérlési folyamat átviteléhez egyértelműen hozzá van rendelve a then_stmt és a else_stmt vagy az stmt végponthoz, ha nincs más záradék.
  • Ha a v állapot az expr végén "határozottan igaz kifejezés után" állapottal rendelkezik, akkor az biztosan hozzá van rendelve a vezérlőfolyamat-átvitelhez then_stmt, és nem feltétlenül van hozzárendelve a vezérlőfolyamat-átvitelhez sem else_stmt, sem az stmt végponthoz, ha nincs más záradék.
  • Ha a v állapot "határozottan hozzárendelve van hamis kifejezés után" az expr végén, akkor az biztosan hozzá van rendelve a vezérlőfolyamat-átvitelhez else_stmt, és nem feltétlenül van hozzárendelve a vezérlőfolyamat-átvitelhez then_stmt. Mindenképpen az stmt végpontján van hozzárendelve, ha és csak akkor, ha határozottan a then_stmt végpontján van hozzárendelve.
  • Ellenkező esetben a v nem feltétlenül van hozzárendelve a vezérlési folyamat átviteléhez sem a then_stmt, sem a else_stmt, sem az stmt végponthoz, ha nincs más záradék.

9.4.4.7 Kapcsoló utasítások

switch Egy vezérlőkifejezést tartalmazó stmt utasítás esetén:

A v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v állapota az stmt elején.

A v végleges hozzárendelési állapota az eset őrzési záradékának elején a következő:

  • Ha v a switch_label deklarált mintaváltozó: "határozottan hozzárendelve".
  • Ha a védő záradékot tartalmazó kapcsolócímke (13.8.3. §) nem érhető el: "határozottan hozzárendelve".
  • Ellenkező esetben a v állapota megegyezik az expr utáni v állapotával.

példa: A második szabály szükségtelenné teszi, hogy egy fordító hibát adjon ki, ha egy nem hozzárendelt változó elérhetetlen kódban érhető el. A b állapota "határozottan hozzárendelve" van a nem elérhető kapcsoló címkéjébencase 2 when b.

bool b;
switch (1) 
{
    case 2 when b: // b is definitely assigned here.
    break;
}

záró példa

A vezérlőfolyamat egy elérhető kapcsolóblokk-utasításlistára való átvitelének v végleges hozzárendelési állapota a következő:

  • Ha a vezérlőátvitel egy "goto-eset" vagy "goto default" utasítás miatt történt, akkor a v állapota megegyezik a "goto" utasítás elején lévő állapottal.
  • Ha a vezérlőátvitel a default kapcsoló címkéje miatt történt, akkor a v állapota megegyezik az expr utáni v állapottal.
  • Ha a vezérlőátvitel egy elérhetetlen kapcsolócímke miatt történt, akkor a v állapota "határozottan hozzárendelve" lesz.
  • Ha a vezérlőátvitelt egy elérhető kapcsolócímke okozta egy védő záradékkal, akkor a v állapota megegyezik az őrzáradék utáni v állapottal.
  • Ha a vezérlőátvitel egy védő záradék nélküli, elérhető kapcsolócímke miatt történt, akkor a v állapota
    • Ha v a switch_label deklarált mintaváltozó: "határozottan hozzárendelve".
    • Ellenkező esetben a v állapota megegyezik a kiutasítás utáni v statisztikával.

Ezeknek a szabályoknak az a következménye, hogy egy switch_label deklarált mintaváltozó a kapcsolószakasz utasításaiban "nem feltétlenül lesz hozzárendelve", ha nem ez az egyetlen elérhető kapcsolócímke a szakaszában.

Példa:

public static double ComputeArea(object shape)
{
    switch (shape)
    {
        case Square s when s.Side == 0:
        case Circle c when c.Radius == 0:
        case Triangle t when t.Base == 0 || t.Height == 0:
        case Rectangle r when r.Length == 0 || r.Height == 0:
            // none of s, c, t, or r is definitely assigned
            return 0;
        case Square s:
            // s is definitely assigned
            return s.Side * s.Side;
        case Circle c:
            // c is definitely assigned
            return c.Radius * c.Radius * Math.PI;
           …
    }
}

záró példa

9.4.4.8 Utasítások

Az űrlap utasítása:

while ( «expr» ) «while_body»
  • a v a kitevő elején ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint az stmt elején.
  • Ha a v az expr végén van hozzárendelve, akkor a vezérlőfolyamat-átvitelhez egyértelműen hozzá van rendelve a while_body és az stmt végpontja felé.
  • Ha v az expr végén a "határozottan hozzárendelt igaz kifejezés után" állapottal rendelkezik, akkor az biztosan hozzá van rendelve a vezérlőfolyamat-átvitelhez while_body, de az stmt végpontján nem.
  • Ha v az expr végén a "határozottan hozzárendelt hamis kifejezés után" állapottal rendelkezik, akkor a vezérlőfolyamat-átvitelhez egyértelműen hozzá van rendelve az stmt végpontjára, de nem feltétlenül van hozzárendelve a vezérlőfolyamat-átvitelhez while_body.

9.4.4.9 Do utasítás

Az űrlap utasítása:

do «do_body» while ( «expr» ) ;
  • a v ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint az stmt elejétől a do_body, mint az stmt elején.
  • a v az expr elején ugyanazzal a határozott hozzárendelési állapottal rendelkezik, mint a do_body végpontján.
  • Ha a v az expr végén van hozzárendelve, akkor az egyértelműen az stmt végpontjára történő vezérlési folyamat átviteléhez van hozzárendelve.
  • Ha a v állapot "határozottan hozzárendelve van hamis kifejezés után" az expr végén, akkor az biztosan hozzá van rendelve a vezérlőfolyamat-átvitelhez az stmt végpontjára, de nem feltétlenül van hozzárendelve a vezérlőfolyamat-átvitelhez do_body.

9.4.4.10 Utasítások esetén

Az űrlap egy nyilatkozatához:

for ( «for_initializer» ; «for_condition» ; «for_iterator» )
    «embedded_statement»

a határozott hozzárendelés ellenőrzése úgy történik, mintha az utasítás meg lett volna írva:

{
    «for_initializer» ;
    while ( «for_condition» )
    {
        «embedded_statement» ;
        LLoop: «for_iterator» ;
    }
}

olyan utasításokkal, continue amelyek a for lefordított utasítást a címkét gotomegcélzó utasításokra LLoop irányulnak. Ha a for_condition nincs megadva az utasításból, akkor a for végleges hozzárendelés kiértékelése úgy folytatódik, mintha for_condition a fenti bővítés során igaz értékre cserélték volna.

9.4.4.11 Törés, folytatás és goto utasítások

A v végleges hozzárendelési állapota az , breakvagy continue utasítás által gotookozott vezérlőfolyamat-átvitelen ugyanaz, mint a v végleges hozzárendelési állapota az utasítás elején.

9.4.4.12 Dobás utasítások

Az űrlap utasítása:

throw «expr» ;

a v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v végleges hozzárendelési állapota az stmt elején.

9.4.4.13 Visszatérési utasítások

Az űrlap utasítása:

return «expr» ;
  • A v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v végleges hozzárendelési állapota az stmt elején.
  • Ha v egy kimeneti paraméter, akkor a következőhöz kell hozzárendelni:
    • az expr után
    • vagy az utasítást tartalmazó finally blokktry-finallytry-catch-finallyvégén.return

Az űrlap utasítása:

return ;
  • Ha v egy kimeneti paraméter, akkor a következőhöz kell hozzárendelni:
    • stmt előtt
    • vagy az utasítást tartalmazó finally blokktry-finallytry-catch-finallyvégén.return

9.4.4.14 Próbálkozási utasítások

Az űrlap utasítása:

try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
  • A v végleges hozzárendelési állapota a try_block elején ugyanaz, mint a v végleges hozzárendelési állapota az stmt elején.
  • A v végleges hozzárendelési állapota a catch_block_i elején (bármely i esetén) megegyezik az stmt elején lévő v végleges hozzárendelési állapotával.
  • Az stmt végpontján lévő v végleges hozzárendelési állapota akkor van egyértelműen hozzárendelve, ha (és csak akkor) v van hozzárendelve a try_block végpontján és minden catch_block_i (minden i esetében 1-től n-ig).

9.4.4.15 Próba-végi utasítások

Az űrlap utasítása:

try «try_block» finally «finally_block»
  • A v végleges hozzárendelési állapota a try_block elején ugyanaz, mint a v végleges hozzárendelési állapota az stmt elején.
  • A v végleges hozzárendelési állapota a finally_block elején ugyanaz, mint a v végleges hozzárendelési állapota az stmt elején.
  • Az stmt végpontján lévő v végleges hozzárendelési állapota akkor van egyértelműen hozzárendelve, ha (és csak akkor), ha az alábbiak közül legalább az egyik igaz:
    • a v egyértelműen a try_block végpontján van hozzárendelve
    • a v egyértelműen a finally_block végpontján van hozzárendelve

Ha olyan vezérlőfolyamat-átvitel (például goto utasítás) történik, amely try_block belül kezdődik, és try_block kívül végződik, akkor a v is határozottan hozzárendeltnek minősül az adott vezérlőfolyamat-átvitelhez, ha a v egyértelműen a finally_block végpontján van hozzárendelve. (Ez nem csak akkor igaz, ha – ha a v-t más okból rendelik hozzá ehhez a vezérlőfolyamat-átvitelhez, akkor továbbra is határozottan hozzárendeltnek tekintik.)

9.4.4.16 Try-catch-finally utasítások

Az űrlap egy nyilatkozatához:

try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
finally «finally_block»

a határozott hozzárendelés elemzése úgy történik, mintha az utasítás egy try-finally utasítást tartalmazó try-catch utasítás volna:

try
{
    try «try_block»
    catch ( ... ) «catch_block_1»
    ...
    catch ( ... ) «catch_block_n»
}
finally «finally_block»

Példa: Az alábbi példa bemutatja, hogy egy try utasítás különböző blokkjai (13.11. §) hogyan befolyásolják a határozott hozzárendelést.

class A
{
    static void F()
    {
        int i, j;
        try
        {
            goto LABEL;
            // neither i nor j definitely assigned
            i = 1;
            // i definitely assigned
        }
        catch
        {
            // neither i nor j definitely assigned
            i = 3;
            // i definitely assigned
        }
        finally
        {
            // neither i nor j definitely assigned
            j = 5;
            // j definitely assigned
        }
        // i and j definitely assigned
        LABEL: ;
        // j definitely assigned
    }
}

záró példa

9.4.4.17 Foreach-utasítások

Az űrlap utasítása:

foreach ( «type» «identifier» in «expr» ) «embedded_statement»
  • A v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v állapota az stmt elején.
  • Az embedded_statement vagy az stmt végpontjára történővezérlési folyamat v végleges hozzárendelési állapota megegyezik az expr végén lévő v állapottal.

9.4.4.18 Utasítások használata

Az űrlap utasítása:

using ( «resource_acquisition» ) «embedded_statement»
  • A v végleges hozzárendelési állapota a resource_acquisition elején ugyanaz, mint a v állapota az stmt elején.
  • A vezérlési folyamat embedded_statement-ra történő átvitelének v végleges hozzárendelési állapota megegyezik a resource_acquisition végén lévő v állapottal.

9.4.4.19 Zárolási utasítások

Az űrlap utasítása:

lock ( «expr» ) «embedded_statement»
  • A v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v állapota az stmt elején.
  • A vezérlési folyamat embedded_statement felé történő átvitelének v végleges hozzárendelési állapota megegyezik az expr végén lévő v állapottal.

9.4.4.20 Hozamkimutatások

Az űrlap utasítása:

yield return «expr» ;
  • A v végleges hozzárendelési állapota az expr elején ugyanaz, mint a v állapota az stmt elején.
  • Az stmt végén lévő v végleges hozzárendelési állapota megegyezik az expr végén lévő v állapottal.

Az yield break utasításnak nincs hatása a határozott hozzárendelés állapotára.

9.4.4.21 Az állandó kifejezések általános szabályai

Az alábbiak minden állandó kifejezésre vonatkoznak, és elsőbbséget élveznek az alábbi szakaszokban szereplő szabályokkal szemben, amelyek alkalmazhatók:

Állandó értékű truekifejezés esetén:

  • Ha a v határozottan a kifejezés előtt van hozzárendelve, akkor a v egyértelműen a kifejezés után lesz hozzárendelve.
  • Ellenkező esetben a v a kifejezés után "határozottan hamis kifejezés után van hozzárendelve".

Példa:

int x;
if (true) {}
else
{
    Console.WriteLine(x);
}

záró példa

Állandó értékű falsekifejezés esetén:

  • Ha a v határozottan a kifejezés előtt van hozzárendelve, akkor a v egyértelműen a kifejezés után lesz hozzárendelve.
  • Ellenkező esetben a v a kifejezés után "határozottan igaz kifejezés után van hozzárendelve".

Példa:

int x;
if (false)
{
    Console.WriteLine(x);
}

záró példa

Az összes többi állandó kifejezés esetében a v végleges hozzárendelési állapota a kifejezés után ugyanaz, mint a v végleges hozzárendelési állapota a kifejezés előtt.

9.4.4.22 Egyszerű kifejezések általános szabályai

A következő szabály az alábbi kifejezésekre vonatkozik: konstansok (§12.8.2), egyszerű nevek (§12.8.4), taghozzáférés-kifejezések (§12.8.7), nem indexelt alapelérési kifejezések (§12.8.15), kifejezések (§12.8.18), alapértelmezett értékkifejezések (§12.8.21), kifejezések (§12.8.23) és deklarációs kifejezések (§12.17).

  • Az ilyen kifejezés végén lévő v végleges hozzárendelési állapota megegyezik a kifejezés elején lévő v végleges hozzárendelési állapotával.

9.4.4.23 A beágyazott kifejezéseket tartalmazó kifejezések általános szabályai

Az ilyen típusú kifejezésekre a következő szabályok vonatkoznak: zárójeles kifejezések (§12.8.5), rendezett n-tuple kifejezések (§12.8.6), elemelérési kifejezések (§12.8.12), alapelérési kifejezések indexeléssel (§12.8.15), növekményes és csökkentés kifejezések (§12.8.16, §12.9.6), kifejezések típuskonverzióval (§12.9.7), unáris +, -, ~, * kifejezések, bináris +, -, *, /, %, <<, >>, <, <=, >, >=, ==, !=, is, as, &, |, ^ kifejezések (§12.10, §12.11, §12.12, §12.13), összetett hozzárendelési kifejezések (§12.21.4), checked és unchecked kifejezések (§12.8.20), tömb- és delegátum létrehozási kifejezések (§12.8.17) és await kifejezések (§12.9.8).

Mindegyik kifejezés egy vagy több olyan alkifejezéssel rendelkezik, amelyeket feltétel nélkül, rögzített sorrendben értékelnek ki.

Példa: A bináris % operátor kiértékeli az operátor bal oldalát, majd a jobb oldalt. Az indexelési művelet kiértékeli az indexelt kifejezést, majd kiértékeli az egyes indexkifejezéseket balról jobbra haladva. záró példa

Az expr kifejezéshez, amelynek kibontása ki van osztva₁, expr₂, ..., exprₓ, az adott sorrendben kiértékelve:

  • A v végleges hozzárendelési állapota az expr₁ elején ugyanaz, mint a végleges hozzárendelési állapot az expr elején.
  • A kiutasítás elején lévő v végleges hozzárendelési állapota (i nagyobb, mint egy) megegyezik a kitérés végén lévő végleges hozzárendelési állapottal₋ ₁.
  • Az expr végén lévő v végleges hozzárendelési állapota megegyezik az exprₓ végén található határozott hozzárendelési állapottal.

9.4.4.24 Meghívási kifejezések és objektumlétrehozási kifejezések

Ha a meghívandó metódus részleges metódus, amely nem implementálja a részleges metódusdeklarációt, vagy olyan feltételes módszer, amelynek a hívását kihagyja (22.5.3.2. §), akkor a meghívás után a v végleges hozzárendelési állapota megegyezik a meghívás előtti v végleges hozzárendelési állapotával. Ellenkező esetben a következő szabályok érvényesek:

Az űrlap meghívási kifejezésének kifejezése :

«primary_expression» ( «arg₁», «arg₂», … , «argₓ» )

vagy az űrlap objektumlétrehozó kifejezésének kifejezése :

new «type» ( «arg₁», «arg₂», … , «argₓ» )
  • Invokációs kifejezés esetén a v végleges hozzárendelési állapota primary_expression előtt megegyezik az expr előtti v állapottal.
  • Invokációs kifejezés esetén az arg₁ előtti v végleges hozzárendelési állapota megegyezik az primary_expression utáni v állapotával.
  • Objektumlétrehozási kifejezés esetén a v végleges hozzárendelési állapota az arg₁ előtt megegyezik a kiff előtti v állapottal.
  • Minden argi argumentum esetében az argi utáni v végleges hozzárendelési állapotát a normál kifejezési szabályok határozzák meg, figyelmen kívül hagyva az esetleges in, outvagy ref módosítókat.
  • Az egyes argumentumok argi minden i nagyobb, az argi előtti v végleges hozzárendelési állapota megegyezik az argi₋₁ utáni v állapotával.
  • Ha a v változó argumentumként van átadva (azaz a "out out" alak argumentuma) az argumentumok bármelyikében, akkor a kiutasítás utáni v állapot biztosan ki lesz rendelve. Ellenkező esetben az expr utáni v állapota megegyezik az argₓ utáni v állapotával.
  • Tömb inicializálók (§12.8.17.4), objektum inicializálók (§12.8.17.2.2), gyűjtemény inicializálók (§12.8.17.2.3) és névtelen objektum inicializálók (§12.8.17.3), a határozott hozzárendelési állapotot az alapján határozzák meg, hogy ezek a konstrukciók milyen kifejtésen alapulnak a definícióik szerint.

9.4.4.25 Egyszerű hozzárendelési kifejezések

Az e kifejezésben a hozzárendelési célok készletét a következőképpen kell definiálni:

  • Ha az e egy rekord kifejezés, akkor az e-beli hozzárendelési célok az e elemek hozzárendelési céljainak egyesítését képezik.
  • Ellenkező esetben a hozzárendelési célértékek e.

Az űrlap kifejezésének kifejezése :

«expr_lhs» = «expr_rhs»
  • A v végleges hozzárendelési állapota expr_lhs előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • A v végleges hozzárendelési állapota expr_rhs előtt ugyanaz, mint a v végleges hozzárendelési állapota expr_lhs után.
  • Ha a v a expr_lhs hozzárendelési célja, akkor az expr után a v végleges hozzárendelési állapota biztosan ki lesz rendelve. Ellenkező esetben, ha a hozzárendelés egy szerkezettípus példánykonstruktorán belül történik, és a v egy automatikusan implementált P tulajdonság rejtett háttérmezője a létrehozandó példányon, és a P tulajdonsághozzáférés a expr_lhs assigment célhelye, akkor a kiutasításután a v végleges hozzárendelési állapota biztosan ki van rendelve. Ellenkező esetben a kiutasítás utáni v végleges hozzárendelési állapota megegyezik a v végleges hozzárendelésiállapota expr_rhs után.

Példa: Az alábbi kódban

class A
{
    static void F(int[] arr)
    {
        int x;
        arr[x = 1] = x; // ok
    }
}

a változót x a második egyszerű hozzárendelés bal oldali elemének kiértékelése után arr[x = 1] határozottan hozzárendeltnek tekintjük.

záró példa

9.4.4.26 > kifejezések

Az űrlap kifejezésének kifejezése :

«expr_first» && «expr_second»
  • A v végleges hozzárendelési állapota expr_first előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • Az expr_second előtti v végleges hozzárendelésiállapota akkor és csak akkor van hozzárendelve, ha a expr_first utáni v állapota egyértelműen ki van rendelve, vagy "a valódi kifejezés után határozottan hozzárendelve". Ellenkező esetben nincs egyértelműen hozzárendelve.
  • A kiutasítás utáni v végleges hozzárendelési állapotát a következő határozza meg:
    • Ha az expr_first után a v állapota egyértelműen ki van rendelve, akkor az expr után a v állapota biztosan ki van rendelve.
    • Ellenkező esetben, ha az expr_second utáni v állapota egyértelműen hozzárendelve van, és a expr_first utáni v állapota "határozottan a hamis kifejezés után van hozzárendelve", akkor az expr után a v állapota egyértelműen ki van rendelve.
    • Ellenkező esetben, ha az expr_second utáni v állapota egyértelműen ki van rendelve, vagy "az igaz kifejezés után határozottan ki van rendelve", akkor az expr utáni v állapota "a valódi kifejezés után határozottan hozzárendelve" lesz.
    • Ellenkező esetben, ha a expr_first utáni v állapota "hamis kifejezés után határozottan hozzárendelve", és a expr_second utáni v állapota "határozottan a hamis kifejezés után van hozzárendelve", akkor az expr utáni v állapot "határozottan a hamis kifejezés után van hozzárendelve".
    • Ellenkező esetben a kiutasítás utáni v állapot nincs hozzárendelve.

Példa: Az alábbi kódban

class A
{
    static void F(int x, int y)
    {
        int i;
        if (x >= 0 && (i = y) >= 0)
        {
            // i definitely assigned
        }
        else
        {
            // i not definitely assigned
        }
        // i not definitely assigned
    }
}

a változót i egyértelműen hozzárendeltnek tekintjük egy if utasítás egyik beágyazott utasításában, a másikban azonban nem. if A metódus Futasításában a változót i mindenképpen az első beágyazott utasításhoz rendeli hozzá, mert a kifejezés (i = y) végrehajtása mindig megelőzi ennek a beágyazott utasításnak a végrehajtását. Ezzel szemben a változó i nem feltétlenül van hozzárendelve a második beágyazott utasításhoz, mivel x >= 0 előfordulhat, hogy hamis tesztet végzett, ami azt eredményezi, hogy a változó inincs hozzárendelve.

záró példa

9.4.4.27 || Kifejezések

Az űrlap kifejezésének kifejezése :

«expr_first» || «expr_second»
  • A v végleges hozzárendelési állapota expr_first előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • Az expr_second előtti v végleges hozzárendelésiállapota akkor és csak akkor van hozzárendelve, ha a expr_first utáni v állapota egyértelműen ki van rendelve, vagy "a valódi kifejezés után határozottan hozzárendelve". Ellenkező esetben nincs egyértelműen hozzárendelve.
  • A kiutasítás utáni v végleges hozzárendelési utasítását a következő határozza meg:
    • Ha az expr_first után a v állapota egyértelműen ki van rendelve, akkor az expr után a v állapota biztosan ki van rendelve.
    • Ellenkező esetben, ha az expr_second utáni v állapota egyértelműen hozzárendelve van, és a expr_first utáni v állapota "határozottan igaz kifejezés után van hozzárendelve", akkor az expr után a v állapota biztosan ki van rendelve.
    • Ellenkező esetben, ha a expr_second utáni v állapota egyértelműen hozzárendelve van, vagy "határozottan a hamis kifejezés után van hozzárendelve", akkor az expr utáni v állapota "a hamis kifejezés után egyértelműen hozzárendelve".
    • Ellenkező esetben, ha a expr_first utáni v állapota "a valódi kifejezés után határozottan van hozzárendelve", és a expr_ másodperc utáni v állapota "határozottan igaz kifejezés után van hozzárendelve", akkor az expr utáni v állapot "határozottan igaz kifejezés után van hozzárendelve".
    • Ellenkező esetben a kiutasítás utáni v állapot nincs hozzárendelve.

Példa: Az alábbi kódban

class A
{
    static void G(int x, int y)
    {
        int i;
        if (x >= 0 || (i = y) >= 0)
        {
            // i not definitely assigned
        }
        else
        {
            // i definitely assigned
        }
        // i not definitely assigned
    }
}

a változót i egyértelműen hozzárendeltnek tekintjük egy if utasítás egyik beágyazott utasításában, a másikban azonban nem. if A metódus Gutasításában a változót i a második beágyazott utasításban rendeli hozzá, mert a kifejezés (i = y) végrehajtása mindig megelőzi ennek a beágyazott utasításnak a végrehajtását. Ezzel szemben a változó i nem feltétlenül van hozzárendelve az első beágyazott utasításhoz, mivel x >= 0 lehet, hogy igaz lett volna tesztelve, ami azt eredményezi, hogy a változó inincs hozzárendelve.

záró példa

9.4.4.28 ! Kifejezések

Az űrlap kifejezésének kifejezése :

! «expr_operand»
  • A v végleges hozzárendelési állapota expr_operand előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • A kiutasítás utáni v végleges hozzárendelési állapotát a következő határozza meg:
    • Ha az expr_operand utáni állapotot v egyértelműen hozzárendeli, akkor a kitevő utáni állapotot v határozottan hozzárendeli.
    • Ellenkező esetben, ha az expr_operandvállapot "hamis kifejezés után egyértelműen van hozzárendelve", akkor az exprvállapot "a valódi kifejezés után határozottan hozzárendelve" lesz.
    • Ellenkező esetben, ha a expr_operandvállapot "a valódi kifejezés után egyértelműen van hozzárendelve", akkor az expr utáni v állapot "a hamis kifejezés után egyértelműen hozzárendelve".
    • Ellenkező esetben a kiutasításvállapot nincs egyértelműen hozzárendelve.

9.4.4.29 ?? Kifejezések

Az űrlap kifejezésének kifejezése :

«expr_first» ?? «expr_second»
  • A v végleges hozzárendelési állapota expr_first előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • A v végleges hozzárendelési állapota expr_second előtt ugyanaz, mint a v végleges hozzárendelési állapota expr_first után.
  • A kiutasítás utáni v végleges hozzárendelési utasítását a következő határozza meg:
    • Ha expr_first egy állandó kifejezés (12.23.§), nullakkor az expr utáni v állapota megegyezik a expr_second utáni állapottal.
    • Ellenkező esetben a kiutasítás utáni v állapota megegyezik a v végleges hozzárendelési állapota expr_first után.

9.4.4.30 ?: kifejezések

Az űrlap kifejezésének kifejezése :

«expr_cond» ? «expr_true» : «expr_false»
  • A v végleges hozzárendelési állapota expr_cond előtt megegyezik a kiff előtti v állapottal.
  • Az expr_true előtti v végleges hozzárendelésiállapota akkor lesz egyértelműen hozzárendelve, ha a expr_cond utáni v állapota egyértelműen ki van rendelve, vagy "a valódi kifejezés után határozottan hozzárendelve".
  • A v végleges hozzárendelési állapota expr_false előtt, ha az expr_cond utáni v állapota egyértelműen ki van rendelve, vagy "a hamis kifejezés után határozottan hozzárendelve".
  • A kiutasítás utáni v végleges hozzárendelési állapotát a következő határozza meg:
    • Ha expr_cond egy állandó kifejezés (12.23.§), true akkor az expr után a v állapota megegyezik a expr_true utáni állapottal.
    • Ellenkező esetben, ha expr_cond egy állandó kifejezés (12.23.§), akkor az expr utáni v állapota falsemegegyezik a expr_false utáni állapottal.
    • Ellenkező esetben, ha a expr_true utáni v állapota egyértelműen ki van rendelve, és az expr_false utáni v állapota egyértelműen ki van rendelve, akkor a kiff utáni v állapota biztosan ki van rendelve.
    • Ellenkező esetben a kiutasítás utáni v állapot nincs hozzárendelve.

9.4.4.31 Névtelen függvények

Egy lambda_expression vagy anonymous_method_expression kifúvatás esetén egy törzs (blokkvagy kifejezés) törzsével:

  • Egy paraméter végleges hozzárendelési állapota megegyezik egy nevesített metódus paraméterével (9.2.6. §, 9.2.7. §, 9.2.8. §).
  • Egy v külső változó végleges hozzárendelési állapota a törzs előtt ugyanaz, mint a kiff előtt lévő v állapot. Vagyis a külső változók határozott hozzárendelési állapota öröklődik a névtelen függvény környezetéből.
  • A külső változó v végleges hozzárendelési állapota az expr után megegyezik a kiff előtti v állapottal.

Példa: A példa

class A
{
    delegate bool Filter(int i);
    void F()
    {
        int max;
        // Error, max is not definitely assigned
        Filter f = (int n) => n < max;
        max = 5;
        DoWork(f);
    }
    void DoWork(Filter f) { ... }
}

fordítási idő hibát okoz, mivel a max nincs egyértelműen hozzárendelve a névtelen függvény deklarálásakor.

záró példa

Példa: A példa

class A
{
    delegate void D();
    void F()
    {
        int n;
        D d = () => { n = 1; };
        d();
        // Error, n is not definitely assigned
        Console.WriteLine(n);
    }
}

fordítási idő hibát is generál, mivel a névtelen függvényhez való n hozzárendelés nincs hatással a névtelen függvényen kívüli végleges hozzárendelési n állapotra.

záró példa

9.4.4.32 Dobókifejezések

Az űrlap kifejezésének kifejezése :

throw thrown_expr

  • A v végleges hozzárendelési állapota thrown_expr előtt megegyezik a kiff előtti v állapottal.
  • A kiutasítás utáni v végleges hozzárendelési állapota "határozottan hozzárendelve".

9.4.4.33 A helyi függvények változóinak szabályai

A rendszer a helyi függvényeket a szülőmetódus kontextusában elemzi. A helyi függvények esetében két vezérlőfolyamat-útvonal számít: függvényhívások és delegálások.

Az egyes helyi függvények törzsének határozott hozzárendelése minden hívási helyhez külön van meghatározva. Minden egyes hívásnál a helyi függvény által rögzített változók akkor tekinthetők egyértelműen hozzárendeltnek, ha a hívás időpontjában egyértelműen hozzárendelték őket. Ezen a ponton egy vezérlőfolyamat-útvonal is létezik a helyi függvény törzséhez, és elérhetőnek tekinthető. A helyi függvény hívása után a rögzített változók, amelyek a függvénytreturn elhagyó minden vezérlőponthoz (utasítások, utasítások, yield kifejezések) lettek hozzárendelve, await a hívás helye után egyértelműen hozzárendeltnek minősülnek.

A delegált konverziók a helyi függvény törzsének vezérlőfolyamat-útvonalával rendelkeznek. A rögzített változók mindenképpen a törzshöz vannak hozzárendelve, ha azokat az átalakítás előtt egyértelműen hozzárendelték. A helyi függvény által hozzárendelt változók nem tekinthetők hozzárendeltnek az átalakítás után.

Megjegyzés: a fentiek azt jelentik, hogy a rendszer minden helyi függvényhívásnál vagy delegálásnál újra elemzi a szerveket a végleges hozzárendeléshez. A fordítóknak nem kell újra elemezniük egy helyi függvény törzsét minden egyes meghíváskor vagy delegáláskor. A megvalósításnak az adott leírásnak megfelelő eredményeket kell eredményeznie. végjegyzet

Példa: Az alábbi példa a helyi függvényekben rögzített változók határozott hozzárendelését mutatja be. Ha egy helyi függvény beolvassa a rögzített változót írás előtt, a rögzített változót mindenképpen ki kell osztani a helyi függvény meghívása előtt. A helyi függvény F1 hozzárendelés nélkül olvas s . Ez egy hiba, ha F1 az előbb van meghívva s , és mindenképpen hozzá van rendelve. F2 hozzárendelést, mielőtt elolvassa i . Lehet, hogy azelőtt hívjuk meg, hogy i biztosan hozzárendelték volna. Továbbá, F3 lehet meghívni után F2 , mert s2 határozottan hozzárendelte a F2.

void M()
{
    string s;
    int i;
    string s2;
   
    // Error: Use of unassigned local variable s:
    F1();
    // OK, F2 assigns i before reading it.
    F2();
    
    // OK, i is definitely assigned in the body of F2:
    s = i.ToString();
    
    // OK. s is now definitely assigned.
    F1();

    // OK, F3 reads s2, which is definitely assigned in F2.
    F3();

    void F1()
    {
        Console.WriteLine(s);
    }
    
    void F2()
    {
        i = 5;
        // OK. i is definitely assigned.
        Console.WriteLine(i);
        s2 = i.ToString();
    }

    void F3()
    {
        Console.WriteLine(s2);
    }
}

záró példa

9.4.4.34 is-pattern kifejezések

Az űrlap kifejezésének kifejezése :

expr_operand minta

  • A v végleges hozzárendelési állapota expr_operand előtt ugyanaz, mint a v végleges hozzárendelésiállapota az expr előtt.
  • Ha a "v" változó mintában van deklarálva, akkor az expr utáni "v" végleges hozzárendelési állapota "határozottan ki van rendelve, ha igaz".
  • Ellenkező esetben a "v" végleges hozzárendelési állapota az expr után ugyanaz, mint a "v" végleges hozzárendelési állapota expr_operand után.

9.5 Változóhivatkozások

A variable_reference egy változóként besorolt kifejezés . A variable_reference egy tárolóhelyet jelöl, amely az aktuális érték lekéréséhez és egy új érték tárolásához is elérhető.

variable_reference
    : expression
    ;

Megjegyzés: A C és a C++-ban a variable_reference nevezik lvalue-nak. végjegyzet

9.6 Változóhivatkozások atomisága

A következő adattípusok olvasásának és írásának atominak kell lennie: bool, char, byte, sbyte, short, ushort, uint, int, , floatés referenciatípusok. Ezenkívül az előző listában alapul szolgáló típusú enumerálási és írási műveleteknek is atominak kell lenniük. Más típusú olvasásoknak és írásoknak, beleértve longa , ulong, double, és decimal, valamint a felhasználó által meghatározott típusokat, nem kell atominak lenniük. Az erre a célra tervezett kódtárfüggvények mellett nincs garancia az atomi olvasás-módosítás-írásra, például növekmény vagy csökkenés esetén.

9.7 Referenciaváltozók és visszatérések

9.7.1 Általános

A referenciaváltozó olyan változó, amely egy másik változóra, az úgynevezett hivatkozásra hivatkozik (9.2.6. §). A referenciaváltozó a módosítóval ref deklarált helyi változó.

A referenciaváltozók egy variable_reference (9.5. §)-t tárolnak a hivatkozó számára, nem pedig a hivatkozás értékét. Ha egy referenciaváltozót használnak, ahol egy értékre van szükség, a hivatkozási értéke lesz visszaadva; Hasonlóképpen, ha egy referenciaváltozó egy hozzárendelés célja, az a hivatkozás, amelyhez hozzá van rendelve. Az a változó, amelyre a referenciaváltozó hivatkozik, azaz a hivatkozáshoz tartozó tárolt variable_reference , módosítható egy újraf-hozzárendeléssel (= ref).

Példa: Az alábbi példa egy helyi referenciaváltozót mutat be, amelynek hivatkozása egy tömb eleme:

public class C
{
    public void M()
    {
        int[] arr = new int[10];
        // element is a reference variable that refers to arr[5]
        ref int element = ref arr[5];
        element += 5; // arr[5] has been incremented by 5
    }     
}

záró példa

A hivatkozási visszatérés a visszatérési módszerből visszaadott variable_reference (15.6.1. §). Ez a variable_reference a hivatkozási visszatérés hivatkozása.

Példa: Az alábbi példa egy hivatkozási visszatérést mutat be, amelynek hivatkozása egy tömbmező eleme:

public class C
{
    private int[] arr = new int[10];

    public ref readonly int M()
    {
        // element is a reference variable that refers to arr[5]
        ref int element = ref arr[5];
        return ref element; // return reference to arr[5];
    }     
}

záró példa

9.7.2 Biztonságos környezetek újrafedés

9.7.2.1 Általános

Minden referenciaváltozó betartja a biztonsági szabályokat, amelyek biztosítják, hogy a referenciaváltozó ref-safe-contextje ne legyen nagyobb, mint a hivatkozás ref-safe-contextje.

Megjegyzés: A biztonságos környezet kapcsolódó fogalma a (16.4.15.)-ben van definiálva, a kapcsolódó megkötésekkel együtt. végjegyzet

Bármely változó esetében a változó ref-safe-contextje az a környezet, amelyben az adott változóra vonatkozó variable_reference (9.5. §) érvényes. A referenciaváltozó hivatkozásának olyan ref-safe-kontextussal kell rendelkeznie, amely legalább olyan széles, mint maga a referenciaváltozó ref-safe-contextje.

Megjegyzés: A fordító a programszöveg statikus elemzésével határozza meg a ref-safe-contextt. A ref-safe-context egy változó futásidejű élettartamát tükrözi. végjegyzet

Három ref-safe-contexts van:

  • deklarációs blokkok: Egy helyi változóra variable_reference (§9.2.9.1) ref-safe-contextje az, hogy a helyi változó hatóköre (§13.6.2), beleértve az adott hatókörbe tartozó beágyazott beágyazott utasításis.

    A helyi változóra variable_reference csak akkor érvényes hivatkozási hivatkozás egy referenciaváltozóhoz, ha a referenciaváltozó a változó ref-safe-kontextusában van deklarálva.

  • függvény-tag: Egy függvényen belül egy variable_reference az alábbiak bármelyikéhez ref-safe-context of function-member:

    • Értékparaméterek (15.6.2.2. §) egy függvénytag-deklaráción, beleértve az osztálytagfüggvények implicit this értékét is; és
    • Egy tagfüggvény implicit hivatkozási (ref) paramétere () a mezőkkel együtt.

    A függvénytag ref-safe-context-környezetével rendelkező variable_reference csak akkor érvényes hivatkozás, ha a referenciaváltozó ugyanabban a függvénytagban van deklarálva.

  • hívókörnyezet: Egy függvényen belül az alábbi variable_reference ref-safe-context hívókörnyezettel rendelkezik:

    • Referenciaparaméterek (9.2.6. §) a strukturált tagfüggvény implicit this kivételével;
    • Az ilyen paraméterek tagmezői és elemei;
    • Osztálytípus paramétereinek tagmezői; és
    • A tömbtípus paramétereinek elemei.

A hívókörnyezet ref-safe-context-környezetével rendelkező variable_reference hivatkozási visszatérés hivatkozása lehet.

Ezek az értékek beágyazási kapcsolatot alkotnak a legszűkebbtől (deklarációs blokktól) a legszélesebbig (hívó-környezet). Minden beágyazott blokk egy másik környezetet jelöl.

Példa: Az alábbi kód a különböző ref-safe-contexts példákat mutatja be. A deklarációk egy változó inicializálási kifejezésének mutatják egy hivatkozó ref-safe-környezetét ref . A példák a hivatkozási visszatérés ref-safe-context értékét mutatják be:

public class C
{
    // ref safe context of arr is "caller-context". 
    // ref safe context of arr[i] is "caller-context".
    private int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    // ref safe context is "caller-context"
    public ref int M1(ref int r1)
    {
        return ref r1; // r1 is safe to ref return
    }

    // ref safe context is "function-member"
    public ref int M2(int v1)
    {
        return ref v1; // error: v1 isn't safe to ref return
    }

    public ref int M3()
    {
        int v2 = 5;

        return ref arr[v2]; // arr[v2] is safe to ref return
    }

    public void M4(int p) 
    {
        int v3 = 6;

        // context of r2 is declaration-block,
        // ref safe context of p is function-member
        ref int r2 = ref p;

        // context of r3 is declaration-block,
        // ref safe context of v3 is declaration-block
        ref int r3 = ref v3;

        // context of r4 is declaration-block,
        // ref safe context of arr[v3] is caller-context
        ref int r4 = ref arr[v3]; 
    }
}

záró példa.

Példa: Típusok esetén struct az implicit this paraméter referenciaparaméterként lesz átadva. A függvénytagként megadott típusú mezők struct ref-safe-contextje megakadályozza, hogy hivatkozási visszatéréssel visszaadja ezeket a mezőket. Ez a szabály megakadályozza a következő kódot:

public struct S
{
     private int n;

     // Disallowed: returning ref of a field.
     public ref int GetN() => ref n;
}

class Test
{
    public ref int M()
    {
        S s = new S();
        ref int numRef = ref s.GetN();
        return ref numRef; // reference to local variable 'numRef' returned
    }
}

záró példa.

9.7.2.2 Helyi változó – biztonságos környezet

Helyi változó vesetén:

  • Ha v referenciaváltozó, akkor a ref-safe-context értéke megegyezik az inicializáló kifejezés ref-safe-környezetével.
  • Ellenkező esetben a ref-safe-context deklarálási blokk.

9.7.2.3 Paraméter – biztonságos környezet

Paraméter pesetén:

  • Ha p referencia- vagy bemeneti paraméter, akkor a ref-safe-context a hívókörnyezet. Ha p egy bemeneti paraméter, az nem írhatóként ref adható vissza, hanem visszaadható.ref readonly
  • Ha p kimeneti paraméter, akkor a ref-safe-context a hívókörnyezet.
  • Ellenkező esetben, ha p egy this struktúratípus paramétere, a ref-safe-context a függvény-tag.
  • Ellenkező esetben a paraméter egy értékparaméter, a ref-safe-context pedig a függvénytag.

9.7.2.4 A mező ref biztonságos környezete

Mezőre mutató hivatkozást e.Fkijelölő változó esetén:

  • Ha e referenciatípus, akkor a ref-safe-context a hívókörnyezet.
  • Ellenkező esetben, ha e érték típusú, a ref-safe-context megegyezik a ref-safe-context of e.

9.7.2.5 Operátorok

A feltételes operátor (12.18. §) c ? ref e1 : ref e2és a referencia-hozzárendelési operátor = ref e (12.21.1. §) operandusként referenciaváltozókkal rendelkezik, és referenciaváltozót eredményez. Ezen operátorok esetében az eredmény ref-safe-contextje a legszűkebb kontextus az összes ref operandus ref-safe-contexts környezetei között.

9.7.2.6 Függvényhívás

A ref-returning függvény meghívásából eredő változók c esetében a ref-safe-context a legszűkebb az alábbi környezetek közül:

  • A hívó környezet.
  • Az összes ref, outés in argumentumkifejezés ref-safe-contextje (a fogadó kivételével).
  • Minden bemeneti paraméter esetében, ha van egy változónak megfelelő kifejezés, és létezik identitáskonverzió a változó típusa és a paraméter típusa között, akkor a változó ref-safe-contextje, ellenkező esetben a legközelebbi beágyazási környezet.
  • Az összes argumentumkifejezés (beleértve a fogadót is) biztonságos környezete (16.4.15. §).

Példa: az utolsó listajelre van szükség a kód kezeléséhez, például

ref int M2()
{
    int v = 5;
    // Not valid.
    // ref safe context of "v" is block.
    // Therefore, ref safe context of the return value of M() is block.
    return ref M(ref v);
}

ref int M(ref int p)
{
    return ref p;
}

záró példa

A tulajdonsághívást és az indexelő-meghívást (vagy getset) a fenti szabályok az alapul szolgáló tartozék függvényhívásaként kezelik. A helyi függvényhívás függvényhívás.

9.7.2.7 Értékek

Az érték ref-safe-contextje a legközelebbi beágyazási környezet.

Megjegyzés: Ez egy olyan meghívásban fordul elő, mint például M(ref d.Length) a where d is of type dynamic. A bemeneti paramétereknek megfelelő argumentumokkal is összhangban van. végjegyzet

9.7.2.8 Konstruktor-meghívások

A new konstruktort meghívó kifejezés ugyanazokat a szabályokat követi, mint egy metódushívás (§9.7.2.6), amely a létrehozott típust adja vissza.

9.7.2.9 A referenciaváltozók korlátozásai

  • Sem a lambda kifejezés, sem a helyi függvény nem rögzíthet referenciaparamétert, sem kimeneti paramétert, sem bemeneti paramétert, sem ref helyi paramétert vagy helyi típust ref struct .
  • Sem a referenciaparaméter, sem a kimeneti paraméter, sem a bemeneti paraméter, sem a ref struct típus paramétere nem lehet argumentum az iterátor módszer vagy metódus async számára.
  • Sem a ref helyi, sem a helyi ref struct típusú nem lehet kontextusban egy yield return állítás vagy kifejezés await pontján.
  • Újbóli hozzárendelés e1 = ref e2esetén a ref-safe-contextnek e2 legalább olyan szélesnek kell lennie , mint a ref-safe-context of e1.
  • A ref return utasítás return ref e1esetében a ref-safe-context a e1 hívó kontextusa.