9 proměnných
9.1 Obecné
Proměnné představují umístění úložiště. Každá proměnná má typ, který určuje, jaké hodnoty lze v proměnné uložit. Jazyk C# je jazyk bezpečný pro typ a kompilátor jazyka C# zaručuje, že hodnoty uložené v proměnných jsou vždy odpovídajícím typem. Hodnotu proměnné lze změnit přiřazením nebo použitím ++
operátorů a --
operátorů.
Proměnná musí být rozhodně přiřazena (§9.4) před získáním jeho hodnoty.
Jak je popsáno vnásledujícíchch Původně přiřazená proměnná má dobře definovanou počáteční hodnotu a vždy se považuje za rozhodně přiřazenou. Počáteční proměnná bez přiřazení nemá žádnou počáteční hodnotu. Pro počáteční nepřiřazenou proměnnou, která má být považována za rozhodně přiřazenou v určitém umístění, se přiřazení proměnné provede ve všech možných spouštěcích cestách, které vedou k danému umístění.
9.2 Kategorie proměnných
9.2.1 Obecné
Jazyk C# definuje osm kategorií proměnných: statické proměnné, proměnné instancí, prvky matice, parametry hodnot, vstupní parametry, referenční parametry, výstupní parametry a místní proměnné. Dílčí seznamy, které následují, popisují každou z těchto kategorií.
Příklad: V následujícím kódu
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
je statická proměnná,y
je proměnná instance,v[0]
je prvek pole,a
je parametr hodnoty,b
je referenční parametr,c
je výstupní parametr,d
je vstupním parametrem ai
je místní proměnná. end example
9.2.2 Statické proměnné
Pole deklarované pomocí modifikátoru static
je statická proměnná. Statická proměnná přichází do existence před provedením konstruktoru static
(§15.12) pro jeho typ, a přestane existovat, když přidružená doména aplikace přestane existovat.
Počáteční hodnota statické proměnné je výchozí hodnota (§9,3) typu proměnné.
Pro účely kontroly určitého přiřazení se statická proměnná považuje za původně přiřazenou.
9.2.3 Proměnné instance
9.2.3.1 Obecné
Pole deklarované bez modifikátoru static
je proměnná instance.
9.2.3.2 Proměnné instancí ve třídách
Proměnná instance třídy přichází do existence při vytvoření nové instance této třídy a přestane existovat, pokud neexistují žádné odkazy na tuto instanci a finalizátor instance (pokud existuje) byl proveden.
Počáteční hodnota proměnné instance třídy je výchozí hodnota (§9.3) typu proměnné.
Pro účely kontroly určitého přiřazení se proměnná instance třídy považuje za původně přiřazenou.
9.2.3.3 Proměnné instancí ve strukturách
Proměnná instance struktury má přesně stejnou životnost jako proměnná struktury, do které patří. Jinými slovy, pokud proměnná typu struktury přichází do existence nebo přestane existovat, tak také udělejte proměnné instance struktury.
Počáteční stav přiřazení proměnné instance struktury je stejný jako stav obsahující struct
proměnné. Jinými slovy, pokud je proměnná struktury považována za původně přiřazenou, jsou to také její proměnné instance a když je proměnná struktury považována za původně nepřiřazenou, její proměnné instance jsou stejně nepřiřazené.
9.2.4 Prvky pole
Prvky pole přicházejí do existence při vytvoření instance pole a přestanou existovat, pokud neexistují žádné odkazy na tuto instanci pole.
Počáteční hodnota každého prvku matice je výchozí hodnota (§9.3) typu prvků matice.
Pro účely kontroly určitého přiřazení se prvek pole považuje za původně přiřazený.
9.2.5 Parametry hodnoty
Parametr hodnoty přichází do existence při vyvolání členu funkce (metoda, konstruktor instance, accessor nebo operátor) nebo anonymní funkce, do které parametr patří, a je inicializován s hodnotou argumentu zadaného ve volání. Parametr hodnoty obvykle přestane existovat, když se dokončí provádění těla funkce. Pokud je však parametr hodnoty zachycen anonymní funkcí (§12.19.6.2), jeho životnost se alespoň prodlouží, dokud delegát nebo strom výrazu vytvořený z této anonymní funkce nemá nárok na uvolňování paměti.
Pro účely kontroly určitého přiřazení se parametr hodnoty považuje za původně přiřazený.
Parametry hodnot jsou popsány dále v §15.6.2.2.
Referenční parametry 9.2.6
Referenční parametr je referenční proměnná (§9.7), která přichází do existence při vyvolání člena funkce, delegáta, anonymní funkce nebo místní funkce a její odkaz je inicializována na proměnnou, která je uvedena jako argument v tomto vyvolání. Po dokončení provádění těla funkce přestane existovat referenční parametr. Na rozdíl od parametrů hodnoty se referenční parametr nezachytí (§9.7.2.9).
Následující pravidla pro určité přiřazení platí pro referenční parametry.
Poznámka: Pravidla pro výstupní parametry se liší a jsou popsána v bodech 9.2.7. koncová poznámka
- Proměnná musí být jednoznačně přiřazena (§9.4) před předáním jako referenční parametr ve vyvolání člena funkce nebo delegáta.
- V rámci člena funkce nebo anonymní funkce se parametr odkazu považuje za původně přiřazený.
Referenční parametry jsou popsány dále v §15.6.2.3.3.
9.2.7 Výstupní parametry
Výstupní parametr je referenční proměnná (§9.7), která přichází do existence při vyvolání člena funkce, delegáta, anonymní funkce nebo místní funkce a její odkaz je inicializována na proměnnou, která je uvedena jako argument v tomto vyvolání. Při dokončení provádění těla funkce přestane existovat výstupní parametr. Na rozdíl od parametrů hodnot se výstupní parametr nezachytí (§9.7.2.9).
Následující pravidla pro určité přiřazení platí pro výstupní parametry.
Poznámka: Pravidla referenčních parametrů se liší a jsou popsána v bodech 9.2.6. koncová poznámka
- Proměnná nemusí být rozhodně přiřazená, než ji lze předat jako výstupní parametr ve volání člena funkce nebo delegáta.
- Po normálním dokončení volání člena funkce nebo delegáta se každá proměnná, která byla předána jako výstupní parametr, považuje za přiřazenou v této cestě spuštění.
- V rámci člena funkce nebo anonymní funkce se výstupní parametr považuje za původně nepřiřazený.
- Každý výstupní parametr člena funkce, anonymní funkce nebo místní funkce musí být rozhodně přiřazen (§9.4) před tím, než se člen funkce, anonymní funkce nebo místní funkce vrátí normálně.
Výstupní parametry jsou popsány dále v §15.6.2.3.4.
9.2.8 Vstupní parametry
Vstupní parametr je referenční proměnná (§9.7), která přichází do existence při vyvolání člena funkce, delegáta, anonymní funkce nebo místní funkce a její odkaz je inicializována na variable_reference zadaný jako argument v tomto vyvolání. Po dokončení provádění těla funkce přestane existovat vstupní parametr. Na rozdíl od parametrů hodnoty se vstupní parametr nezachytí (§9.7.2.9).
Následující pravidla přiřazení se vztahují na vstupní parametry.
- Proměnná musí být jednoznačně přiřazena (§9.4), než ji lze předat jako vstupní parametr při vyvolání člena funkce nebo delegáta.
- V rámci člena funkce, anonymní funkce nebo místní funkce se vstupní parametr považuje za původně přiřazený.
Vstupní parametry jsou popsány dále v §15.6.2.3.2.
9.2.9 Místní proměnné
9.2.9.1 Obecné
Místní proměnná je deklarována local_variable_declaration, declaration_expression, foreach_statement nebo specific_catch_clausetry_statement. Místní proměnnou lze deklarovat také určitými druhy vzorů (§11). Pro foreach_statement je místní proměnná iterační proměnnou (§13.9.5). Pro specific_catch_clause je místní proměnná proměnnou výjimky (§13.11). Místní proměnná deklarovaná foreach_statement nebo specific_catch_clause se považuje za původně přiřazenou.
K local_variable_declaration může dojít v bloku, for_statement, switch_block nebo using_statement. Declaration_expression může nastat jako out
a jako tuple_element, který je cílem dekonstrukčního přiřazení (§12.21.2).
Životnost místní proměnné je část provádění programu, během které je zaručeno, že úložiště je pro něj vyhrazeno. Tato doba života se prodlužuje od vstupu do oboru, ke kterému je přidružena, alespoň do konce provádění tohoto oboru nějakým způsobem. (Zadání uzavřeného bloku, volání metody nebo výnosu hodnoty z bloku iterátoru se pozastaví, ale nekončí, spuštění aktuálního oboru.) Pokud je místní proměnná zachycena anonymní funkcí (§12.19.6.2), jeho životnost se prodlouží alespoň do doby, než delegát nebo strom výrazu vytvořený z anonymní funkce spolu s dalšími objekty, které odkazují na zachycenou proměnnou, jsou způsobilé pro uvolňování paměti. Pokud je nadřazený obor zadán rekurzivně nebo iterativním způsobem, vytvoří se pokaždé nová instance místní proměnné a její inicializátor (pokud existuje) se při každém vyhodnocení vyhodnotí.
Poznámka: Místní proměnná se vytvoří instance při každém zadání oboru. Toto chování je viditelné pro uživatelský kód obsahující anonymní metody. koncová poznámka
Poznámka: Životnost proměnné iterace (§13.9.5) deklarované foreach_statement je jedinou iterací tohoto příkazu. Každá iterace vytvoří novou proměnnou. koncová poznámka
Poznámka: Skutečná životnost místní proměnné je závislá na implementaci. Kompilátor může například staticky určit, že místní proměnná v bloku se používá jenom pro malou část tohoto bloku. Pomocí této analýzy by kompilátor mohl vygenerovat kód, který vede k tomu, že úložiště proměnné má kratší životnost než jeho blok obsahující.
Úložiště, na které odkazuje místní referenční proměnná, se uvolní nezávisle na životnosti této místní referenční proměnné (§7.9).
koncová poznámka
Místní proměnná zavedená local_variable_declaration nebo declaration_expression není automaticky inicializována, a proto nemá výchozí hodnotu. Taková místní proměnná se považuje za původně nepřiřazenou.
Poznámka: Local_variable_declaration , která obsahuje inicializátor, je stále nepřiřazeno. Provedení deklarace se chová přesně jako přiřazení proměnné (§9.4.4.5). Použití proměnné před spuštěním inicializátoru; Například v samotném výrazu inicializátoru nebo pomocí goto_statement , který inicializátor obchází; je chyba v době kompilace:
goto L; int x = 1; // never executed L: x += 1; // error: x not definitely assigned
V rámci oboru místní proměnné se jedná o chybu v době kompilace odkazující na tuto místní proměnnou v textové pozici, která předchází jeho deklarátoru.
koncová poznámka
9.2.9.2 Zahození
Zahození je místní proměnná, která nemá žádný název. Zahození je zavedeno výrazem deklarace (§12.17) s identifikátorem _
; a je buď implicitně zadán (_
nebo var _
) nebo explicitně zadán (T _
).
Poznámka:
_
je platný identifikátor v mnoha formách deklarací. koncová poznámka
Vzhledem k tomu, že zahození nemá žádný název, jediným odkazem na proměnnou, kterou představuje, je výraz, který jej zavádí.
Poznámka: Zahození lze však předat jako výstupní argument, což umožňuje odpovídajícímu výstupnímu parametru označit jeho přidružené umístění úložiště. koncová poznámka
Zahození není původně přiřazeno, takže se vždy zobrazí chyba pro přístup k jeho hodnotě.
Příklad:
_ = "Hello".Length; (int, int, int) M(out int i1, out int i2, out int i3) { ... } (int _, var _, _) = M(out int _, out var _, out _);
Příklad předpokládá, že v oboru neexistuje žádná deklarace názvu
_
.Přiřazení, které zobrazí
_
jednoduchý vzor pro ignorování výsledku výrazu.M
Volání ukazuje různé formy zahození dostupné v řazených kolekcích členů a jako výstupní parametry.end example
9.3 Výchozí hodnoty
Následující kategorie proměnných se automaticky inicializují na výchozí hodnoty:
- Statické proměnné.
- Proměnné instance instancí instancí.
- Prvky pole.
Výchozí hodnota proměnné závisí na typu proměnné a je určena následujícím způsobem:
- Pro proměnnou value_type je výchozí hodnota stejná jako hodnota vypočítaná výchozím konstruktorem value_type (§8.3.3).
- Pro proměnnou reference_type je
null
výchozí hodnota .
Poznámka: Inicializace na výchozí hodnoty se obvykle provádí tak, že správce paměti nebo uvolňování paměti inicializuje paměť na all-bits-zero před tím, než je přidělen k použití. Z tohoto důvodu je vhodné použít all-bits-nu reprezentovat nulový odkaz. koncová poznámka
9.4 Určení zadání
9.4.1 Obecné
V daném umístění ve spustitelném kódu člena funkce nebo anonymní funkce se říká, že proměnná je rozhodně přiřazena pokud kompilátor může prokázat konkrétní statickou analýzou toku (§9.4.4), že proměnná byla automaticky inicializována nebo byla cílem alespoň jednoho přiřazení.
Poznámka: Neformálně uvedeno, pravidla určitého přiřazení jsou:
- Počáteční přiřazená proměnná (§9.4.2) se vždy považuje za rozhodně přiřazenou.
- Počáteční nepřiřazená proměnná (§9.4.3) je považována za rozhodně přiřazenou v daném umístění, pokud všechny možné cesty provádění vedoucí k tomuto umístění obsahují alespoň jednu z následujících možností:
- Jednoduché přiřazení (§12.21.2), ve kterém je proměnná levým operandem.
- Výraz vyvolání (§12.8.10) nebo výraz vytvoření objektu (§12.8.17.2), který předá proměnnou jako výstupní parametr.
- Pro místní proměnnou je deklarace místní proměnné pro proměnnou (§13.6.2), která obsahuje inicializátor proměnných.
Formální specifikace výše uvedených neformálních pravidel je popsána v bodech 9.4.2, §9.4.3 a §9.4.4.
koncová poznámka
Určité stavy přiřazení proměnných instance struct_type proměnné jsou sledovány jednotlivě i souhrnně. Kromě pravidel popsaných v §9.4.2, §9.4.3 a §9.4.4 platí následující pravidla pro struct_type proměnné a jejich proměnné instance:
- Proměnná instance je považována za rozhodně přiřazenou, pokud je její obsahující struct_type proměnná považována za rozhodně přiřazenou.
- Proměnná struct_type je považována za rozhodně přiřazenou, pokud je každá z jejích proměnných instance považována za rozhodně přiřazenou.
Určité přiřazení je požadavek v následujících kontextech:
Proměnná musí být rozhodně přiřazena v každém umístění, kde je získána jeho hodnota.
Poznámka: Tím zajistíte, že se nedefinované hodnoty nikdy neskončí. koncová poznámka
Výskyt proměnné ve výrazu se považuje za získání hodnoty proměnné s výjimkou případů, kdy
- proměnná je levý operand jednoduchého přiřazení,
- proměnná se předává jako výstupní parametr nebo
- proměnná je struct_type proměnná a vyskytuje se jako levý operand přístupu člena.
Proměnná musí být jednoznačně přiřazena v každém umístění, kde se předává jako referenční parametr.
Poznámka: Tím zajistíte, že vyvolaný člen funkce může zvážit počáteční přiřazený referenční parametr. koncová poznámka
Proměnná musí být rozhodně přiřazena v každém umístění, kde se předává jako vstupní parametr.
Poznámka: Tím zajistíte, že vyvolaný člen funkce může nejprve zvážit vstupní parametr. koncová poznámka
Všechny výstupní parametry člena funkce musí být rozhodně přiřazeny v každém umístění, kde se člen funkce vrátí (prostřednictvím návratového příkazu nebo provedením dosažení konce členu funkce).
Poznámka: Tím zajistíte, aby členové funkce nevraceli nedefinované hodnoty ve výstupních parametrech, čímž kompilátoru umožní zvážit vyvolání člena funkce, který vezme proměnnou jako výstupní parametr ekvivalentní přiřazení proměnné. koncová poznámka
Proměnná
this
konstruktoru instance struct_type musí být rozhodně přiřazena v každém umístění, kde tento konstruktor instance vrátí.
9.4.2 Počáteční přiřazené proměnné
Následující kategorie proměnných jsou klasifikovány jako původně přiřazené:
- Statické proměnné.
- Proměnné instance instancí instancí.
- Proměnné instance počátečních přiřazených proměnných struktury
- Prvky pole.
- Parametry hodnot.
- Referenční parametry
- Vstupní parametry:
- Proměnné deklarované v
catch
klauzuli neboforeach
příkazu
9.4.3 Zpočátku nepřiřazené proměnné
Následující kategorie proměnných jsou klasifikovány jako původně nepřiřazené:
- Proměnné instance počátečních nepřiřazených proměnných struktury
- Výstupní parametry, včetně
this
proměnné konstruktoru instance struktury bez inicializátoru konstruktoru. - Místní proměnné s výjimkou těch deklarovaných v
catch
klauzuli neboforeach
příkazu.
9.4.4 Přesná pravidla pro stanovení určitého přiřazení
9.4.4.1 Obecné
Aby bylo možné určit, že každá použitá proměnná je rozhodně přiřazená, kompilátor použije proces, který je ekvivalentní tomu, který je popsaný v tomto dílčím seznamu.
Tělo člena funkce může deklarovat jednu nebo více počátečních nepřiřazených proměnných. Pro každou počáteční nepřiřazenou proměnnou vurčí kompilátor určitý stav přiřazení pro v v každém z následujících bodů člena funkce:
- Na začátku každého příkazu
- V koncovém bodě (§13.2) každého prohlášení
- Na každém oblouku, který přenáší řízení do jiného příkazu nebo na koncový bod příkazu
- Na začátku každého výrazu
- Na konci každého výrazu
Konečný stav přiřazení v může být následující:
- Rozhodně přiřazeno. To znamená, že u všech možných toků řízení k tomuto bodu byla přiřazena hodnota.
- Rozhodně nepřiřazené. Pro stav proměnné na konci výrazu typu
bool
spadá stav proměnné, která není rozhodně přiřazená (ale nemusí) spadat do jednoho z následujících dílčích stavů:- Rozhodně přiřazený po skutečném výrazu. Tento stav označuje, že v je rozhodně přiřazen, pokud se logický výraz vyhodnotí jako pravdivý, ale nemusí být nutně přiřazen, pokud se logický výraz vyhodnotí jako nepravda.
- Rozhodně přiřazený po nepravdivém výrazu. Tento stav označuje, že v je rozhodně přiřazen, pokud se logický výraz vyhodnotí jako nepravda, ale nemusí být nutně přiřazen, pokud se logický výraz vyhodnotí jako pravdivý.
Následující pravidla určují, jak se stav proměnné v určuje v každém umístění.
9.4.4.2 Obecná pravidla pro prohlášení
- v není rozhodně přiřazen na začátku členu funkce.
- Určitý stav přiřazení v na začátku jakéhokoli jiného příkazu je určen kontrolou stavu určitého přiřazení v u všech přenosů toku řízení, které cílí na začátek tohoto příkazu. Pokud (a pouze pokud) v je rozhodně přiřazen ke všem takovým přenosům toku řízení, pakje rozhodně přiřazen na začátku příkazu. Soubor možných přenosů toku řízení je určen stejným způsobem jako pro kontrolu dostupnosti kontrolního prohlášení (§13.2).
- Určitý stav přiřazení v na konci
block
bodu ,checked
, ,unchecked
,if
while
do
for
foreach
lock
using
neboswitch
prohlášení je určen kontrolou stavu neurčitého přiřazení v u všech přenosů toku řízení, které cílí na koncový bod tohoto prohlášení. Pokud je rozhodně přiřazena ke všem takovým přenosům toku řízení, pakje rozhodně přiřazena na konci prohlášení. V opačném případě není rozhodně přiřazen v koncovém bodě příkazu. Soubor možných přenosů toku řízení je určen stejným způsobem jako pro kontrolu dostupnosti kontrolního prohlášení (§13.2).
Poznámka: Vzhledem k tomu, že neexistují žádné řídicí cesty k nedostupným příkazům, v je rozhodně přiřazen na začátku jakéhokoli nedostupného příkazu. koncová poznámka
9.4.4.3 Příkazy bloku, zaškrtnuté a nezaškrtnuté příkazy
Konkrétní stav přiřazení v kontrolního převodu na první příkaz seznamu příkazů v bloku (nebo na koncový bod bloku, pokud je seznam příkazů prázdný) je stejný jako příkaz určitého přiřazení v před blokem, checked
nebo unchecked
příkazem.
9.4.4.4 Výrazové příkazy
Výrazový příkaz stmt, který se skládá z výrazu výrazu:
- v má stejný stav určitého přiřazení na začátku výrazu jako na začátku stmt.
- Pokud je hodnota v rozhodně přiřazena na konci výrazu, je rozhodně přiřazena na konci stmt; jinak není rozhodně přiřazena na koncovém bodu stmt.
9.4.4.5 Prohlášení
- Pokud stmt je příkaz deklarace bez inicializátorů, pak v má stejný určitý stav přiřazení na konci stmt jako na začátku stmt.
- Pokud stmt je deklarační příkaz s inicializátory, pak je určen určitý stav přiřazení pro v , jako by stmt byl seznam příkazů, s jedním příkazem přiřazení pro každou deklaraci s inicializátorem (v pořadí deklarace).
9.4.4.6 Příkazy If
Pro příkaz stmt formuláře:
if ( «expr» ) «then_stmt» else «else_stmt»
- v má stejný stav určitého přiřazení na začátku výrazu jako na začátku stmt.
- Pokud je hodnota v rozhodně přiřazena na konci výrazu, pak je rozhodně přiřazena k přenosu toku řízení do then_stmt a k else_stmt nebo ke koncovému bodu stmt, pokud neexistuje žádná jiná klauzule.
- Pokud má stav "rozhodně přiřazený po skutečném výrazu" na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do then_stmt a rozhodně není přiřazen k přenosu toku řízení do else_stmt nebo do koncového bodu stmt, pokud neexistuje žádná jiná klauzule.
- Pokud má stav "rozhodně přiřazený po nepravdivé výraz" na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do else_stmt a rozhodně není přiřazen k přenosu toku řízení do then_stmt. To je rozhodně přiřazeno na konci stmt pokud a pouze pokud je rozhodně přiřazena na koncovém bodu then_stmt.
- Jinak se hodnota v nepovažuje za jednoznačně přiřazenou k přenosu toku řízení do then_stmt nebo else_stmt nebo do koncového bodu stmt, pokud neexistuje žádná jiná klauzule.
9.4.4.7 Switch – příkazy
switch
Příkaz stmt s řídicím výrazem výrazu:
Určitý stav přiřazení v na začátku výrazu je stejný jako stav v na začátku stmt.
Určitý stav přiřazení v na začátku ochranné klauzule případu je
- Pokud je proměnná vzoru deklarovaná v switch_label: "rozhodně přiřazeno".
- Pokud popisek přepínače obsahující tuto ochranné doložku (§13.8.3) není dosažitelný: "rozhodně přiřazeno".
- V opačném případě je stav v stejný jako stav v po výrazu.
Příklad: Druhé pravidlo eliminuje potřebu kompilátoru vydat chybu, pokud je nepřiřazená proměnná přístupná v nedostupném kódu. Stav b je "rozhodně přiřazen" v nedostupném popisku
case 2 when b
přepínače .bool b; switch (1) { case 2 when b: // b is definitely assigned here. break; }
end example
Určitý stav přiřazení v převodu toku řízení do seznamu blokových příkazů dosažitelného přepínače je
- Pokud byl přenos ovládacích prvků způsoben příkazem goto case nebo goto default, stav v je stejný jako stav na začátku tohoto příkazu goto.
- Pokud byl přenos ovládacích prvků způsoben
default
popiskem přepínače, je stav v stejný jako stav v po výrazu. - Pokud byl přenos ovládacího prvku způsoben nedostupným popiskem přepínače, pak je stav v "rozhodně přiřazen".
- Pokud byl přenos ovládacích prvků způsoben dosažitelným popiskem přepínače s klauzulí stráže, je stav v stejný jako stav v po ochranné klauzuli.
- Pokud byl přenos ovládacích prvků způsoben popiskem dosažitelného přepínače bez ochranné klauzule, stav v je
- Pokud je proměnná vzoru deklarovaná v switch_label: "rozhodně přiřazeno".
- V opačném případě je stav v stejný jako stav v po výrazu.
Důsledkem těchto pravidel je, že proměnná vzoru deklarovaná v switch_label nebude v příkazech oddílu přepínače "rozhodně přiřazena", pokud není jediným dostupným popiskem přepínače v jeho oddílu.
Příklad:
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; … } }
end example
9.4.4.8 Příkazy While
Pro příkaz stmt formuláře:
while ( «expr» ) «while_body»
- v má stejný stav určitého přiřazení na začátku výrazu jako na začátku stmt.
- Pokud je v rozhodně přiřazen na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do while_body a do koncového bodu stmt.
- Pokud má stav "rozhodně přiřazený po skutečném výrazu" na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do while_body, ale rozhodně není přiřazen na konci stmt.
- Pokud má stav "rozhodně přiřazený po nepravdivé výraz" na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do koncového bodu stmt, ale není rozhodně přiřazený k přenosu toku řízení do while_body.
9.4.4.9 Příkazy Do
Pro příkaz stmt formuláře:
do «do_body» while ( «expr» ) ;
- v má stejný stav určitého přiřazení pro přenos toku řízení od začátku stmt do do_body jako na začátku stmt.
- v má stejný stav určitého přiřazení na začátku výrazu jako v koncovém bodě do_body.
- Pokud je v rozhodně přiřazen na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do koncového bodu stmt.
- Pokud má stav "rozhodně přiřazený po nepravdivé výraz" na konci výrazu, pak je rozhodně přiřazen k přenosu toku řízení do koncového bodu stmt, ale není rozhodně přiřazený k přenosu toku řízení do do_body.
9.4.4.10 Pro příkazy
Příkaz formuláře:
for ( «for_initializer» ; «for_condition» ; «for_iterator» )
«embedded_statement»
kontrola určitého přiřazení se provádí tak, jako kdyby bylo zapsáno prohlášení:
{
«for_initializer» ;
while ( «for_condition» )
{
«embedded_statement» ;
LLoop: «for_iterator» ;
}
}
příkazy continue
, které cílí na for
příkazy, které jsou přeloženy na goto
příkazy, které cílí na popisek LLoop
.
Pokud for_condition z prohlášení vynechátefor
, hodnocení konečného přiřazení pokračuje, jako by for_condition byly nahrazeny true ve výše uvedeném rozšíření.
9.4.4.11 Break, continue a goto – příkazy
Určitý stav přiřazení v převodu toku řízení způsobeného break
, continue
nebo goto
příkaz je stejný jako stav určitého přiřazení v na začátku příkazu.
9.4.4.12 Příkazy Throw
Pro příkaz stmt formuláře:
throw «expr» ;
určitý stav přiřazení v na začátku výrazu je stejný jako konečný stav přiřazení v na začátku stmt.
9.4.4.13 Return – příkazy
Pro příkaz stmt formuláře:
return «expr» ;
- Určitý stav přiřazení v na začátku výrazu je stejný jako konečný stav přiřazení v na začátku stmt.
-
Pokud v je výstupní parametr, pak se rozhodně přiřadí:
- po výrazu
- nebo na konci
finally
blokutry
-finally
nebotry
-catch
-finally
, který tento příkaz uzavře.return
Pro příkaz stmt formuláře:
return ;
-
Pokud v je výstupní parametr, pak se rozhodně přiřadí:
- před stmt
- nebo na konci
finally
blokutry
-finally
nebotry
-catch
-finally
, který tento příkaz uzavře.return
9.4.4.14 Příkazy Try-catch
Pro příkaz stmt formuláře:
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
- Určitý stav přiřazení v na začátku try_block je stejný jako určitý stav přiřazení v na začátku stmt.
- Určitý stav přiřazení v na začátku catch_block_i (pro libovolnou i) je stejný jako konečný stav přiřazení v na začátku stmt.
- Určitý stav přiřazení v na konci stmt je rozhodně přiřazen, pokud (a pouze pokud) v je rozhodně přiřazen na koncovém bodu try_block a každý catch_block_i (pro každý i od 1 do n).
9.4.4.15 Příkazy Try-finally
Pro příkaz stmt formuláře:
try «try_block» finally «finally_block»
- Určitý stav přiřazení v na začátku try_block je stejný jako určitý stav přiřazení v na začátku stmt.
- Určitý stav přiřazení v na začátku finally_block je stejný jako konečný stav přiřazení v na začátku stmt.
- Určitý stav přiřazení v na konci stmt je rozhodně přiřazen, pokud (a pouze pokud) alespoň jedna z následujících hodnot je pravdivá:
- v je rozhodně přiřazen na konci try_block
- v je rozhodně přiřazen na konci finally_block
Pokud je proveden přenos toku řízení (například goto
příkaz), který začíná v rámci try_block a končí mimo try_block, pak se hodnota v také považuje za rozhodně přiřazenou k přenosu toku řízení, pokud je v rozhodně přiřazena v koncovém bodu finally_block. (To není jen v případě, že je v rozhodně přiřazen z jiného důvodu pro tento přenos toku řízení, pak se stále považuje za rozhodně přiřazené.)
9.4.4.16 Příkazy Try-catch-finally
Příkaz formuláře:
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
finally «finally_block»
určité analýzy přiřazení se provádí, jako by příkaz byl try
-finally
příkaz, který ohraničuje try
-catch
příkaz:
try
{
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
}
finally «finally_block»
Příklad: Následující příklad ukazuje, jak různé bloky
try
prohlášení (§13.11) ovlivňují určité přiřazení.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 } }
end example
9.4.4.17 Příkazy Foreach
Pro příkaz stmt formuláře:
foreach ( «type» «identifier» in «expr» ) «embedded_statement»
- Určitý stav přiřazení v na začátku výrazu je stejný jako stav v na začátku stmt.
- Konečný stav přiřazení hodnoty v pro přenos toku řízení do embedded_statement nebo do koncového bodu stmt je stejný jako stav v na konci výrazu.
9.4.4.18 Using – příkazy
Pro příkaz stmt formuláře:
using ( «resource_acquisition» ) «embedded_statement»
- Určitý stav přiřazení v na začátku resource_acquisition je stejný jako stav v na začátku stmt.
- Stav určitého přiřazení hodnoty v pro přenos toku řízení do embedded_statement je stejný jako stav v na konci resource_acquisition.
9.4.4.19 Příkazy Lock
Pro příkaz stmt formuláře:
lock ( «expr» ) «embedded_statement»
- Určitý stav přiřazení v na začátku výrazu je stejný jako stav v na začátku stmt.
- Určitý stav přiřazení v pro přenos toku řízení do embedded_statement je stejný jako stav v na konci výrazu.
9.4.4.20 Příkazy Yield
Pro příkaz stmt formuláře:
yield return «expr» ;
- Určitý stav přiřazení v na začátku výrazu je stejný jako stav v na začátku stmt.
- Určitý stav přiřazení v na konci stmt je stejný jako stav v na konci výrazu.
Prohlášení yield break
nemá žádný vliv na stav určitého přiřazení.
9.4.4.21 Obecná pravidla pro konstantní výrazy
Následující platí pro libovolný konstantní výraz a má přednost před všemi pravidly z následujících částí, které by mohly platit:
Pro konstantní výraz s hodnotou true
:
- Pokud je hodnota v rozhodně přiřazena před výrazem, pakje rozhodně přiřazena za výrazem.
- V opačném případě je za výrazem "rozhodně přiřazený po nepravdivém výrazu".
Příklad:
int x; if (true) {} else { Console.WriteLine(x); }
end example
Pro konstantní výraz s hodnotou false
:
- Pokud je hodnota v rozhodně přiřazena před výrazem, pakje rozhodně přiřazena za výrazem.
- V opačném případě je za výrazem "rozhodně přiřazeno po skutečném výrazu".
Příklad:
int x; if (false) { Console.WriteLine(x); }
end example
Pro všechny ostatní konstantní výrazy je konečný stav přiřazení v za výrazem stejný jako konečný stav přiřazení v před výrazem.
9.4.4.22 Obecná pravidla pro jednoduché výrazy
Následující pravidlo se vztahuje na tyto druhy výrazů: literály (
- Určitý stav přiřazení v na konci takového výrazu je stejný jako konečný stav přiřazení v na začátku výrazu.
9.4.4.23 Obecná pravidla pro výrazy s vloženými výrazy
Následující pravidla platí pro tyto druhy výrazů: závorkové výrazy (§12.8.5), výrazy n-tic (§12.8.6), výrazy přístupu prvků (§12.8.12), výrazy základního přístupu s indexováním (§12.8.15), inkrementační a dekrementační výrazy (§12.8.16, §12.9.6), přetypovací výrazy (§12.9.7), unární +
, -
, ~
, *
výrazy, binární +
, -
, *
, /
, %
, <<
, >>
, <
, <=
, >
, >=
, ==
, !=
, is
, as
, &
, |
, ^
výrazy (§12.10, §12.11, §12.12, §12.13), složené výrazy přiřazení (§12.21.4), checked
a unchecked
výrazy (§12.8.20), výrazy vytváření polí a delegátů (§12.8.17), a výrazy await
(§12.9.8).
Každý z těchto výrazů má jeden nebo více dílčích výrazů, které jsou bezpodmínečně vyhodnoceny v pevném pořadí.
Příklad: Binární
%
operátor vyhodnotí levou stranu operátoru a pak pravou stranu. Operace indexování vyhodnocuje indexovaný výraz a vyhodnocuje každý z výrazů indexu v pořadí odleva doprava. end example
Výraz výrazu, který má výrazy výrazů₁, výrazů, ..., výrazₓ, vyhodnocen v daném pořadí:
- Určitý stav přiřazení v na začátku výrazu₁ je stejný jako konečný stav přiřazení na začátku výrazu.
- Určitý stav přiřazení v na začátku expri (i větší než jeden) je stejný jako konečný stav přiřazení na konci expri₋₁.
- Určitý stav přiřazení v na konci výrazu je stejný jako konečný stav přiřazení na konci výrazuₓ.
9.4.4.24 Výrazy volání a výrazy pro vytváření objektů
Je-li vyvolána metoda částečná metoda, která nemá žádnou implementaci částečné deklarace metody, nebo je podmíněná metoda, pro kterou je volání vynecháno (§22.5.3.2), je stav určitého přiřazení v po vyvolání stejný jako stav určitého přiřazení v před vyvoláním. V opačném případě platí následující pravidla:
Výraz vyvolání formuláře:
«primary_expression» ( «arg₁», «arg₂», … , «argₓ» )
nebo výraz pro vytvoření objektu formuláře:
new «type» ( «arg₁», «arg₂», … , «argₓ» )
- Pro vyvolání výrazu je konečný stav přiřazení v před primary_expression stejný jako stav v před výrazem.
- Pro vyvolání výrazu je konečný stav přiřazení v před arg₁ stejný jako stav v po primary_expression.
- Pro výraz vytvoření objektu je určitý stav přiřazení v před arg₁ je stejný jako stav v před výrazem.
- Pro každý argument argi je určitý stav přiřazení v po argi určen pravidly normálního výrazu, ignorování libovolných
in
, ,out
neboref
modifikátorů. - Pro každý argument argi pro libovolný i větší než jeden, určitý stav přiřazení v před argi je stejný jako stav v po argi₋₁.
- Pokud je proměnná v předána jako argument (tj. argument formuláře "out
out
") v některém z argumentů, pak je stav v po výrazu rozhodně přiřazen. V opačném případě je stav v after výraz stejný jako stav vpo argₓ. - Inicializátory pole (§12.8.17.5), inicializátory objektů (§12.8.17.3), inicializátory kolekce (§12.8.17.4) a anonymní inicializátory objektů (§12.8.17.7) mají stav přiřazení určený expandováním, na kterém jsou tyto konstrukce založeny.
9.4.4.25 Jednoduché výrazy přiřazení
Nechte sadu cílů přiřazení ve výrazu e definovat takto:
- Pokud e je výraz řazené kolekce členů, pak cíle přiřazení v e jsou sjednocení cílů přiřazení prvků e.
- V opačném případě jsou cíle přiřazení v e.
Výraz výrazu ve formuláři:
«expr_lhs» = «expr_rhs»
- Určitý stav přiřazení v před expr_lhs je stejný jako konečný stav přiřazení v před výrazem.
- Určitý stav přiřazení v před expr_rhs je stejný jako konečný stav přiřazení v po expr_lhs.
- Pokud je cílem přiřazení expr_lhs, pak je rozhodně přiřazen stav v po výrazu. V opačném případě, pokud přiřazení nastane v rámci konstruktoru instance typu struktury a v je skryté backing pole automaticky implementované vlastnosti P na instanci, která se vytváří, a přístup k vlastnosti označující P je assigment cíl expr_lhs, pak je konečný stav přiřazení v po výrazu rozhodně přiřazen. V opačném případě je určitý stav přiřazení v po výrazu stejný jako konečný stav přiřazení v po expr_rhs.
Příklad: V následujícím kódu
class A { static void F(int[] arr) { int x; arr[x = 1] = x; // ok } }
proměnná
x
se považuje za jednoznačně přiřazenou poarr[x = 1]
vyhodnocení jako levá strana druhého jednoduchého přiřazení.end example
9.4.4.26 & výrazy
Výraz výrazu ve formuláři:
«expr_first» && «expr_second»
- Určitý stav přiřazení v před expr_first je stejný jako konečný stav přiřazení v před výrazem.
- Určitý stav přiřazení v před expr_second je rozhodně přiřazen, pokud a pouze pokud stav v po expr_first je buď rozhodně přiřazen nebo "rozhodně přiřazen po skutečném výrazu". Jinak to není rozhodně přiřazeno.
- Určitý stav přiřazení v po výrazu je určen:
- Pokud stav v po expr_first je rozhodně přiřazen, pak stav v po výrazu je rozhodně přiřazen.
- V opačném případě, pokud stav v po expr_second je rozhodně přiřazen a stav v po expr_first je "rozhodně přiřazen po nepravdivé výraz", stav v po výrazu je rozhodně přiřazen.
- V opačném případě, pokud stav v po expr_second je rozhodně přiřazen nebo "rozhodně přiřazen po skutečném výrazu", stav v after výraz je "rozhodně přiřazen po skutečném výrazu".
- V opačném případě, pokud stav v po expr_first je "rozhodně přiřazen po nepravdivé výraz", a stav v po expr_second je "rozhodně přiřazen po nepravdivé výraz", stav v po výrazu je "rozhodně přiřazen po nepravdivé výraz".
- V opačném případě není stav v po výrazu rozhodně přiřazen.
Příklad: V následujícím kódu
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 } }
proměnná
i
je považována za rozhodně přiřazenou v jednom z vložených příkazůif
příkazu, ale ne v druhém.if
V příkazu v metoděF
je proměnnái
rozhodně přiřazena v prvním vloženém příkazu, protože spuštění výrazu(i = y)
vždy předchází spuštění tohoto vloženého příkazu. Naproti tomu proměnnái
není v druhém vloženém příkazu rozhodně přiřazená, protožex >= 0
mohla být testována nepravda, což vede k tomu, že proměnnái
je nepřiřazená.end example
9.4.4.27 || výrazy
Výraz výrazu ve formuláři:
«expr_first» || «expr_second»
- Určitý stav přiřazení v před expr_first je stejný jako konečný stav přiřazení v před výrazem.
- Určitý stav přiřazení v před expr_second je rozhodně přiřazen, pokud a pouze pokud stav v po expr_first je buď rozhodně přiřazen nebo "rozhodně přiřazen po skutečném výrazu". Jinak to není rozhodně přiřazeno.
- Prohlášení o určitém přiřazení výrazu v po výrazu je určeno:
- Pokud stav v po expr_first je rozhodně přiřazen, pak stav v po výrazu je rozhodně přiřazen.
- V opačném případě, pokud stav v po expr_second je rozhodně přiřazen a stav v po expr_first je "rozhodně přiřazen po skutečném výrazu", stav v po výrazu je rozhodně přiřazen.
- V opačném případě, pokud stav v po expr_second je rozhodně přiřazen nebo "rozhodně přiřazen po nepravdivé výraz", stav v after výraz je "rozhodně přiřazen po nepravdivé výraz".
- Jinak platí, že pokud je stav v po expr_first "rozhodně přiřazen po skutečném výrazu" a stav v po expr_ sekunda je "rozhodně přiřazen po skutečném výrazu", pak stav v po výrazu je "rozhodně přiřazen po skutečném výrazu".
- V opačném případě není stav v po výrazu rozhodně přiřazen.
Příklad: V následujícím kódu
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 } }
proměnná
i
je považována za rozhodně přiřazenou v jednom z vložených příkazůif
příkazu, ale ne v druhém.if
V příkazu v metoděG
je proměnnái
rozhodně přiřazena ve druhém vloženém příkazu, protože spuštění výrazu(i = y)
vždy předchází spuštění tohoto vloženého příkazu. Naproti tomu proměnnái
není v prvním vloženém příkazu rozhodně přiřazená, protožex >= 0
mohla být otestována pravda, což vede k tomu, že proměnnái
není nepřiřazená.end example
9.4.4.28 ! výrazy
Výraz výrazu ve formuláři:
! «expr_operand»
- Určitý stav přiřazení v před expr_operand je stejný jako konečný stav přiřazení v před výrazem.
- Určitý stav přiřazení v po výrazu je určen:
- Pokud je stav
v
po expr_operand rozhodně přiřazen, pak stavv
po výrazu je rozhodně přiřazen. - V opačném případě, pokud je stav
v
po expr_operand "rozhodně přiřazen po nepravdivé výraz", pak stavv
po výrazu je "rozhodně přiřazen po skutečném výrazu". - V opačném případě, pokud je stav
v
po expr_operand "rozhodně přiřazen po skutečném výrazu", pak stav v after výraz je "rozhodně přiřazen po nepravdivé výraz". - V opačném případě není stav
v
po výrazu rozhodně přiřazen.
- Pokud je stav
9.4.4.29 ?? výrazy
Výraz výrazu ve formuláři:
«expr_first» ?? «expr_second»
- Určitý stav přiřazení v před expr_first je stejný jako konečný stav přiřazení v před výrazem.
- Určitý stav přiřazení v před expr_second je stejný jako určitý stav přiřazení v po expr_first.
- Prohlášení o určitém přiřazení výrazu v po výrazu je určeno:
- Je-li expr_first konstantní výraz (§12,23) s hodnotou
null
, je stav v po výrazu stejný jako stav v po expr_second. - V opačném případě je stav v po výrazu stejný jako určitý stav přiřazení v po expr_first.
- Je-li expr_first konstantní výraz (§12,23) s hodnotou
9.4.4.30 ?: výrazy
Výraz výrazu ve formuláři:
«expr_cond» ? «expr_true» : «expr_false»
- Určitý stav přiřazení v před expr_cond je stejný jako stav v před výrazem.
- Určitý stav přiřazení v před expr_true je rozhodně přiřazen, pokud stav v po expr_cond je rozhodně přiřazen nebo "rozhodně přiřazen po skutečném výrazu".
- Určitý stav přiřazení v před expr_false je rozhodně přiřazen, pokud stav v po expr_cond je rozhodně přiřazen nebo "rozhodně přiřazen po nepravdivé výraz".
- Určitý stav přiřazení v po výrazu je určen:
- Je-li expr_cond konstantní výraz (§12,23) s hodnotou
true
, je stav v po výrazu stejný jako stav v po expr_true. - V opačném případě je-li expr_cond konstantní výraz (§12.23) s hodnotou
false
, je stav v po výrazu stejný jako stav v po expr_false. - V opačném případě, pokud stav v po expr_true je rozhodně přiřazen a stav v po expr_false je rozhodně přiřazen, stav v po výrazu je rozhodně přiřazen.
- V opačném případě není stav v po výrazu rozhodně přiřazen.
- Je-li expr_cond konstantní výraz (§12,23) s hodnotou
9.4.4.31 Anonymní funkce
Pro lambda_expression nebo anonymous_method_expression výraz s tělem (blokem nebo výrazem):
- Určitý stav přiřazení parametru je stejný jako u parametru pojmenované metody (§9.2.6, §9.2.7, §9.2.8).
- Konečný stav přiřazení vnější proměnné v před tělem je stejný jako stav v před výrazem. To znamená, že určitý stav přiřazení vnějších proměnných je zděděný z kontextu anonymní funkce.
- Konečný stav přiřazení vnější proměnné v po výrazu je stejný jako stav v před výrazem.
Příklad: Příklad
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) { ... } }
generuje chybu v době kompilace, protože maximální hodnota není rozhodně přiřazena, kde je anonymní funkce deklarována.
end example
Příklad: Příklad
class A { delegate void D(); void F() { int n; D d = () => { n = 1; }; d(); // Error, n is not definitely assigned Console.WriteLine(n); } }
generuje také chybu v době kompilace, protože přiřazení
n
do anonymní funkce nemá žádný vliv na stav určitého přiřazenín
mimo anonymní funkci.end example
9.4.4.32 Výrazy throw
Výraz výrazu ve formuláři:
throw
thrown_expr
- Určitý stav přiřazení v před thrown_expr je stejný jako stav v před výrazem.
- Určitý stav přiřazení v po výrazu je "rozhodně přiřazen".
9.4.4.33 Pravidla pro proměnné v místních funkcích
Místní funkce jsou analyzovány v kontextu jejich nadřazené metody. Existují dvě cesty toku řízení, které jsou důležité pro místní funkce: volání funkcí a delegování převodů.
Určité přiřazení pro tělo každé místní funkce je definováno samostatně pro každou lokalitu volání. Při každém vyvolání se proměnné zachycené místní funkcí považují za rozhodně přiřazené, pokud byly jednoznačně přiřazeny v okamžiku volání. V tomto okamžiku existuje také cesta toku řízení k místnímu textu funkce a je považována za dosažitelnou. Po volání místní funkce se zachycené proměnné, které byly jednoznačně přiřazeny v každém řídicím bodě, který opustil funkci (return
příkazy, yield
příkazy, await
výrazy) jsou považovány za rozhodně přiřazené po umístění volání.
Převody delegátů mají cestu toku řízení k místnímu textu funkce. Zachycené proměnné jsou rozhodně přiřazeny pro tělo, pokud jsou rozhodně přiřazeny před převodem. Proměnné přiřazené místní funkcí se po převodu nepovažují za přiřazené.
Poznámka: Výše uvedené napovídá, že těla se znovu analyzují pro určité přiřazení při každém vyvolání místní funkce nebo převodu delegáta. Kompilátory nejsou potřeba k opětovné analýze těla místní funkce při každém vyvolání nebo delegování převodu. Implementace musí vytvořit výsledky odpovídající danému popisu. koncová poznámka
Příklad: Následující příklad ukazuje určité přiřazení zachycených proměnných v místních funkcích. Pokud místní funkce před zápisem přečte zachycenou proměnnou, musí být zachycená proměnná před voláním místní funkce rozhodně přiřazena. Místní funkce
F1
čte bezs
přiřazení. Jedná se o chybu, pokudF1
je volána dříves
, je rozhodně přiřazena.F2
přiřadíi
před jeho přečtením. Může být volána dřívei
, než je rozhodně přiřazena. DáleF3
může být volána poF2
, protožes2
je rozhodně přiřazena .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); } }
end example
9.4.4.34 is-pattern expressions
Výraz výrazu ve formuláři:
expr_operand je vzor
- Určitý stav přiřazení v před expr_operand je stejný jako konečný stav přiřazení v před výrazem.
- Pokud je proměnná "v" deklarována ve vzoru, pak je konečný stav přiřazení "v" po výrazu "rozhodně přiřazen, pokud je true".
- V opačném případě je konečný stav přiřazení "v" po výrazu stejný jako konečný stav přiřazení "v" po expr_operand.
9.5 Odkazy na proměnné
Variable_reference je výraz, který je klasifikován jako proměnná. Variable_reference označuje umístění úložiště, ke kterému je možné získat přístup jak k aktuální hodnotě, tak k uložení nové hodnoty.
variable_reference
: expression
;
Poznámka: V jazyce C a C++ se variable_reference označuje jako lvalue. koncová poznámka
9.6 Atomicita odkazů na proměnné
Čtení a zápisy následujících datových typů musí být atomické: bool
, char
, byte
, , sbyte
short
, ushort
, uint
, int
float
a odkazové typy. Kromě toho čtení a zápisy typů výčtu s podkladovým typem v předchozím seznamu musí být také atomické. Čtení a zápisy jiných typů, včetně long
ulong
, , double
a decimal
, a také uživatelsky definovaných typů, nemusí být atomické. Kromě funkcí knihovny navržených pro tento účel neexistuje žádná záruka atomového zápisu pro úpravy čtení, například v případě přírůstku nebo dekrementace.
9.7 Referenční proměnné a návraty
9.7.1 Obecné
Referenční proměnná je proměnná, která odkazuje na jinou proměnnou, která se nazývá referent (§9.2.6). Referenční proměnná je místní proměnná deklarovaná s modifikátorem ref
.
Referenční proměnná ukládá variable_reference (§9.5) na odkaz, nikoli hodnotu referentu. Pokud se použije referenční proměnná, kde je požadována hodnota odkazující je vrácena; podobně, pokud je referenční proměnná cílem přiřazení, je to odkaz, ke kterému je přiřazen. Proměnná, na kterou odkazuje referenční proměnná, tj. uložená variable_reference pro odkaz, lze změnit pomocí přiřazení odkazu (= ref
).
Příklad: Následující příklad ukazuje místní referenční proměnnou, jejíž odkaz je prvek pole:
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 } }
end example
Návrat odkazu je variable_reference vrácená metodou return-by-ref (§15.6.1). Tento variable_reference je odkazem návratu odkazu.
Příklad: Následující příklad ukazuje návrat odkazu, jehož odkaz je prvek pole pole:
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]; } }
end example
9.7.2 Referenční bezpečné kontexty
9.7.2.1 Obecné
Všechny referenční proměnné dodržují bezpečnostní pravidla, která zajišťují, aby odkazově bezpečný kontext referenční proměnné nebyl větší než kontext ref-safe odkazující proměnné.
Poznámka: Související pojem bezpečného kontextu je definován v (§16.4.12) spolu s přidruženými omezeními. koncová poznámka
Pro každou proměnnou je kontext odkaz-safe-kontext této proměnné kontext, kde variable_reference (§9.5) této proměnné je platný. Odkaz referenční proměnné musí mít odkazově bezpečný kontext, který je alespoň tak široký jako kontext ref-safe samotné referenční proměnné.
Poznámka: Kompilátor určuje kontext ref-safe prostřednictvím statické analýzy textu programu. Kontext ref-safe odráží životnost proměnné za běhu. koncová poznámka
Existují tři kontexty ref-safe:
bloku deklarace: Referenční kontext variable_reference místní proměnné (§9.2.9.1) je rozsah místní proměnné (§13.6.2), včetně všech vnořených vloženýchv tomto rozsahu.
Variable_reference k místní proměnné je platným odkazem pro referenční proměnnou pouze v případě, že je referenční proměnná deklarována v kontextu ref-safe-kontext této proměnné.
člen funkce: V rámci funkce variable_reference k některé z následujících funkcí má odkazově bezpečný kontext člena funkce:
- Parametry hodnot (§15.6.2.2) u deklarace člena funkce, včetně implicitní
this
členské funkce třídy; - Parametr implicitního odkazu (
ref
§ 15.6.2.3.3)this
členské funkce struktury spolu s jeho poli.
Variable_reference s odkazem bezpečným kontextem člena funkce je platným odkazem pouze v případě, že je referenční proměnná deklarována ve stejném členu funkce.
- Parametry hodnot (§15.6.2.2) u deklarace člena funkce, včetně implicitní
kontext volajícího: V rámci funkce variable_reference na některou z následujících možností má odkazově bezpečný kontext kontextu volajícího:
- Referenční parametry (§9.2.6) jiné než implicitní
this
členová funkce struktury; - Členské pole a prvky těchto parametrů;
- Pole členů parametrů typu třídy; a
- Prvky parametrů typu pole
- Referenční parametry (§9.2.6) jiné než implicitní
Variable_reference s odkazem na bezpečný kontext kontextu volajícího může být odkazem na návrat odkazu.
Tyto hodnoty tvoří vztah vnoření z nejužšího (blok deklarace) na nejširší (kontext volajícího). Každý vnořený blok představuje jiný kontext.
Příklad: Následující kód ukazuje příklady různých kontextů ref-safe-context. Deklarace zobrazují kontext ref-safe-safe pro odkaz, který má být inicializační výraz pro proměnnou
ref
. Příklady ukazují kontext ref-safe pro návrat odkazu: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]; } }
koncový příklad.
Příklad: Pro
struct
typy se implicitníthis
parametr předává jako referenční parametr. Kontext ref-safe-kontext polístruct
typu jako člen funkce zabraňuje vrácení těchto polí návratem odkazu. Toto pravidlo zabraňuje následujícímu kódu: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 } }
koncový příklad.
9.7.2.2 Místní proměnný ref bezpečný kontext
Pro místní proměnnou v
:
- Pokud
v
je referenční proměnná, její odkazově bezpečný kontext je stejný jako kontext ref-safe jeho inicializačního výrazu. - V opačném případě je jeho ref-safe-kontext deklarací blok.
9.7.2.3 Kontext bezpečného odkazu parametru
Pro parametr p
:
- Pokud
p
je odkaz nebo vstupní parametr, jeho ref-safe-context je kontext volajícího. Pokudp
je vstupní parametr, nelze ho vrátit jako zapisovatelnýref
, ale může být vrácen jakoref readonly
. - Pokud
p
je výstupní parametr, jeho ref-safe-context je kontext volajícího. - Jinak je-li
p
this
parametr typu struktury, jeho ref-safe-context je člen funkce. - V opačném případě je parametr hodnotou a jeho ref-safe-context je člen funkce.
9.7.2.4 Kontext bezpečného referenčního pole
Pro proměnnou označující odkaz na pole: e.F
- Pokud
e
je typu odkazu, jeho odkaz-bezpečný kontext je kontext volajícího. - V opačném případě je-li
e
typ hodnoty, jeho ref-safe-kontext je stejný jako kontext ref-safe-kontext .e
9.7.2.5 – operátory
Podmíněný operátor (§12.18) c ? ref e1 : ref e2
a operátor přiřazení odkazu (= ref e
§12.21.1) má referenční proměnné jako operandy a poskytuje referenční proměnnou. Pro tyto operátory je odkazově bezpečný kontext výsledku nejužším kontextem mezi kontexty ref-safe-contexts všech ref
operandů.
9.7.2.6 Vyvolání funkce
Pro proměnnou c
, která je výsledkem vyvolání funkce vracející odkaz, je její kontext ref-safe nejužší z následujících kontextů:
- Kontext volajícího.
- Kontext ref-safe všech
ref
výrazů ,out
ain
argumentů (s výjimkou příjemce). - U každého vstupního parametru existuje odpovídající výraz, který je proměnnou a existuje převod identity mezi typem proměnné a typem parametru, kontext ref-safe-context proměnné, jinak nejbližší uzavřený kontext.
- Bezpečný kontext (§16.4.12) všech výrazů argumentů (včetně příjemce).
Příklad: Poslední odrážka je nezbytná ke zpracování kódu, například
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; }
end example
Vyvolání vlastnosti a vyvolání indexeru (nebo get
set
) se považuje za vyvolání funkce souvisejícího přístupového objektu podle výše uvedených pravidel. Vyvolání místní funkce je vyvolání funkce.
9.7.2.7 Hodnoty
Referenční kontext hodnoty je nejbližší uzavřený kontext.
Poznámka: K tomu dochází při vyvolání, například
M(ref d.Length)
kded
je typudynamic
. Je také konzistentní s argumenty odpovídajícími vstupním parametrům. koncová poznámka
9.7.2.8 Vyvolání konstruktoru
Výraz new
, který vyvolá konstruktor, dodržuje stejná pravidla jako vyvolání metody (§9.7.2.6), která je považována za vrácení typu, který je vytvořen.
9.7.2.9 Omezení referenčních proměnných
- Parametr odkazu ani výstupní parametr ani vstupní parametr ani
ref
místní ani parametr ani místníref struct
parametr typu se nezachytí výrazem lambda nebo místní funkcí. - Parametr odkazu ani výstupní parametr ani vstupní parametr ani parametr
ref struct
typu nesmí být argumentem pro metodu iterátoru ani metoduasync
. -
ref
Místní ani místníref struct
typ nesmí být v kontextu v okamžikuyield return
příkazu nebo výrazuawait
. - Pro opětovné přiřazení
e1 = ref e2
odkazu musí být kontexte2
ref-safe-kontext alespoň tak široký jako kontext ref-safe-kontexte1
. - Pro příkaz
return ref e1
ref return musí být kontext ref-safe-contexte1
volajícího.
ECMA C# draft specification