Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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, helyii
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 (out
12.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ásM
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ásbanforeach
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ásbanforeach
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
bool
vé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 , , ,
block
checked
unchecked
if
while
do
for
foreach
vagylock
utasítás végpontjánusing
hatá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, checked
vagy 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ében
case 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 goto
megcé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 , break
vagy continue
utasítás által goto
okozott 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
-finally
try
-catch
-finally
vé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
-finally
try
-catch
-finally
vé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ű true
kifejezé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ű false
kifejezé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 (
- 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
,out
vagyref
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ánarr[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 egyif
utasítás egyik beágyazott utasításában, a másikban azonban nem.if
A metódusF
utasításában a változóti
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, mivelx >= 0
előfordulhat, hogy hamis tesztet végzett, ami azt eredményezi, hogy a változói
nincs 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 egyif
utasítás egyik beágyazott utasításában, a másikban azonban nem.if
A metódusG
utasításában a változóti
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, mivelx >= 0
lehet, hogy igaz lett volna tesztelve, ami azt eredményezi, hogy a változói
nincs 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 állapototv
határozottan hozzárendeli. - Ellenkező esetben, ha az expr_operand
v
á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_operand
v
á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ás
v
állapot nincs egyértelműen hozzárendelve.
- Ha az expr_operand utáni állapotot
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.§),
null
akkor 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.
- Ha expr_first egy állandó kifejezés (12.23.§),
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
false
megegyezik 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.
- Ha expr_cond egy állandó kifejezés (12.23.§),
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ésin
á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 olvass
. Ez egy hiba, haF1
az előbb van meghívvas
, és mindenképpen hozzá van rendelve.F2
hozzárendelést, mielőtt elolvassai
. Lehet, hogy azelőtt hívjuk meg, hogyi
biztosan hozzárendelték volna. Továbbá,F3
lehet meghívni utánF2
, merts2
határozottan hozzárendelte aF2
.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 long
a , 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.
- Értékparaméterek (15.6.2.2. §) egy függvénytag-deklaráción, beleértve az osztálytagfüggvények implicit
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.
- Referenciaparaméterek (9.2.6. §) a strukturált tagfüggvény implicit
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 implicitthis
paraméter referenciaparaméterként lesz átadva. A függvénytagként megadott típusú mezőkstruct
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ó v
eseté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 p
esetén:
- Ha
p
referencia- vagy bemeneti paraméter, akkor a ref-safe-context a hívókörnyezet. Hap
egy bemeneti paraméter, az nem írhatókéntref
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
egythis
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.F
kijelö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 ofe
.
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
ésin
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 get
set
) 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 whered
is of typedynamic
. 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ípustref 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ódusasync
számára. - Sem a
ref
helyi, sem a helyiref struct
típusú nem lehet kontextusban egyyield return
állítás vagy kifejezésawait
pontján. - Újbóli hozzárendelés
e1 = ref e2
esetén a ref-safe-contextneke2
legalább olyan szélesnek kell lennie , mint a ref-safe-context ofe1
. - A ref return utasítás
return ref e1
esetében a ref-safe-context ae1
hívó kontextusa.
ECMA C# draft specification