Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
16.1 Obecné
Struktury jsou podobné třídám, které představují datové struktury, které mohou obsahovat datové členy a členy funkce. Na rozdíl od tříd jsou však struktury typy hodnot a nevyžadují přidělení haldy. Proměnná struct typu přímo obsahuje data struct, zatímco proměnná typu třídy obsahuje odkaz na data, druhá známá jako objekt.
Poznámka: Struktury jsou zvláště užitečné pro malé datové struktury, které mají sémantiku hodnot. Komplexní čísla, body v souřadnicovém systému nebo páry klíč-hodnota ve slovníku jsou dobrými příklady struktur. Klíčem k těmto datovým strukturám je, že mají málo datových členů, že nevyžadují použití dědičnosti nebo sémantiky odkazu, spíše je možné je pohodlně implementovat pomocí sémantiky hodnot, kde přiřazení zkopíruje hodnotu místo odkazu. koncová poznámka
Jak je popsáno v §8.3.5, jednoduché typy poskytované jazykem C#, například int, doublea bool, jsou ve skutečnosti všechny typy struktur.
16.2 Deklarace struktury
16.2.1 Obecné
Struct_declaration je type_declaration (§14.7), která deklaruje novou strukturu:
struct_declaration
: attributes? struct_modifier* 'ref'? 'partial'? 'struct'
identifier type_parameter_list? struct_interfaces?
type_parameter_constraints_clause* struct_body ';'?
;
Struct_declaration se skládá z volitelné sady atributů (§23), po níž následuje volitelná sada struct_modifiers (§16.2.2), po níž následuje volitelný ref modifikátor (§16.2.3), za kterým následuje volitelný částečný modifikátor (§15.2.7), za kterým následuje klíčové slovo struct a identifikátor, který pojmenuje strukturu, poté volitelnou specifikaci type_parameter_list (§15.2.3) následovanou nepovinným struct_interfaces specifikaci (§16.2.5), po níž následuje volitelná specifikace type_parameter_constraints-klauzulí (§15.2.5), za nimiž následuje struct_body (§16.2.6), případně následuje středník.
Deklarace struktury nesmí poskytovat type_parameter_constraints_clauses, pokud také neposkytuje type_parameter_list.
Deklarace struktury, která poskytuje type_parameter_list je obecná deklarace struktury. Kromě toho každá struktura vnořená uvnitř obecné deklarace třídy nebo obecná deklarace struktury je sama o sobě obecnou deklaraci struktury, protože argumenty typu pro obsahující typ musí být zadány k vytvoření konstruovaného typu (§8.4).
Deklarace struktury, která obsahuje ref klíčové slovo, nesmí mít struct_interfaces část.
16.2.2 Modifikátory struktury
Struct_declaration může volitelně obsahovat posloupnost struct_modifiers:
struct_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| 'readonly'
| unsafe_modifier // unsafe code support
;
unsafe_modifier (§24.2) je k dispozici pouze v nebezpečném kódu (§24).
Jedná se o chybu v době kompilace, aby se stejný modifikátor zobrazoval vícekrát v deklaraci struktury.
readonlyKromě toho mají modifikátory deklarace struktury stejný význam jako modifikátory deklarace třídy (§15.2.2).
readonly Modifikátor označuje, že struct_declaration deklaruje typ, jehož instance jsou neměnné.
Struktura jen pro čtení má následující omezení:
- Každé z jeho polí instance je rovněž deklarováno
readonly. - Nebude deklarovat žádné události podobné proměnným (§15.8.2).
Když je instance struktury jen pro čtení předána metodě, jeho this je považován za vstupní argument/parametr, který zakáže přístup k zápisu do všech polí instance (s výjimkou konstruktorů).
16.2.3 Modifikátor ref
ref Modifikátor označuje, že struct_declaration deklaruje typ, jehož instance jsou přiděleny v zásobníku provádění. Tyto typy se nazývají ref struct typy.
ref Modifikátor deklaruje, že instance mohou obsahovat pole typu ref-like a nesmí být zkopírována z bezpečného kontextu (§16.4.15). Pravidla pro určení bezpečného kontextu struktury odkazu jsou popsána v §16.4.15.
Jedná se o chybu v době kompilace, pokud se typ struktury ref používá v některém z následujících kontextů:
- Jako typ prvku pole.
- Jako deklarovaný typ pole třídy nebo struktury, která nemá
refmodifikátor. - Být omezen na
System.ValueTypeneboSystem.Object. - Jako argument typu.
- Jako typ prvku n-tice.
- Asynchronní metoda.
- Iterátor.
- Neexistuje žádný převod z
ref structtypu na typobjectnebo typSystem.ValueType. - Typ
ref structnesmí být deklarován k implementaci žádného rozhraní. - Metoda instance, která je deklarovaná v
objectnebo vSystem.ValueType, ale není přepsána v typuref struct, nesmí být volána na instanci tohoto typuref struct. - Metoda instance typu
ref structnemá být zachycena konverzí skupiny metod na typ delegáta. - Struktura ref se nezachytí výrazem lambda ani místní funkcí.
Poznámka: Nesmí
ref structdeklarovatasyncmetody instance ani v rámci metody instance použítyield returnaniyield breakpříkaz, protože implicitníthisparametr nelze použít v těchto kontextech. koncová poznámka
Tato omezení zajišťují, že proměnná typu ref struct neodkazuje na paměť zásobníku, která již není platná, nebo na proměnné, které již nejsou platné.
16.2.4 Částečný modifikátor
partial Modifikátor označuje, že tento struct_declaration je částečná deklarace typu. Více částečných deklarací struktury se stejným názvem v rámci uzavřené deklarace oboru názvů nebo typu je kombinováno tak, aby vytvořilo jednu deklaraci struktury podle pravidel uvedených v §15.2.7.
16.2.5 Rozhraní struktur
Deklarace struktury může obsahovat specifikaci struct_interfaces, v takovém případě se říká, že struktura přímo implementuje dané typy rozhraní. Pro konstruovaný typ struktury, včetně vnořeného typu deklarovaného v rámci obecné deklarace typu (§15.3.9.7), je každý typ implementovaného rozhraní získán nahrazením každého type_parameter v daném rozhraní, odpovídající type_argument konstruovaného typu.
struct_interfaces
: ':' interface_type_list
;
Zpracování rozhraní na více částech částečné deklarace struktury (§15.2.7) je dále popsáno v §15.2.4.3.
Implementace rozhraní jsou dále popsány v §19.6.
16.2.6 Tělo struktury
struct_body struktury definuje členy struktury.
struct_body
: '{' struct_member_declaration* '}'
;
16.3 Členy struktury
Členové struktury se skládají z členů zavedených jeho struct_member_declaration, a členů zděděných z typu System.ValueType.
struct_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| operator_declaration
| constructor_declaration
| static_constructor_declaration
| type_declaration
| fixed_size_buffer_declaration // unsafe code support
;
fixed_size_buffer_declaration (§24.8.2) je k dispozici pouze v nebezpečném kódu (§24).
Poznámka: Všechny druhy class_member_declarations s výjimkou finalizer_declaration jsou také struct_member_declarations. koncová poznámka
S výjimkou rozdílů uvedených v §16.4 se popisy členů třídy uvedené v §15.3 až §15.12 vztahují i na členy struktury.
16.4 Rozdíly ve třídě a struktuře
16.4.1 Obecné
Struktury se liší od tříd několika důležitými způsoby:
- Struktury jsou hodnotové typy (§16.4.2).
- Všechny typy struktur implicitně dědí z třídy
System.ValueType(§16.4.3). - Přiřazení proměnné typu struktury vytvoří kopii přiřazené hodnoty (§16.4.4).
- Výchozí hodnota struktury je hodnota vytvořená nastavením všech polí na výchozí hodnotu (§16.4.5).
- Operace boxování a unboxování se používají k převodu mezi typem struktury a určitými referenčními typy (§16.4.6).
-
thisVýznam se liší v rámci členů struktury (§16.4.7). - Deklarace polí instance pro strukturu nesmí obsahovat inicializátory proměnných (§16.4.8).
- Struktura není povolena k deklaraci konstruktoru instance bez parametrů (§16.4.9).
- Struktura nesmí deklarovat finalizátor.
- Deklarace událostí, deklarace vlastností, přístupové metody vlastnosti, deklarace indexeru a deklarace metody mohou mít modifikátor
readonly, i když to není obecně povoleno pro ty samé členy ve třídách.
16.4.2 Sémantika hodnot
Struktury jsou hodnotové typy (§8.3) a říká se, že mají sémantiku hodnot. Třídy jsou na druhou stranu referenčními typy (§8.2) a mají sémantiku odkazu.
Proměnná typu struktury přímo obsahuje data struktury, zatímco proměnná typu třídy obsahuje odkaz na objekt, který obsahuje data. Pokud struktura B obsahuje instanční pole typu A a A je typem struktury, je to chyba při kompilaci, pokud A závisí na B nebo na typu vytvořeném z B. Struktura Xpřímo závisí na struktury Y, pokud X obsahuje pole instance typu Y. Vzhledem k této definici je úplná množina struktur, na nichž závisí daná struktura, tranzitivní uzávěr relace přímé závislosti.
Příklad:
struct Node { int data; Node next; // error, Node directly depends on itself }je chyba, protože
Nodeobsahuje pole instance vlastního typu. Další příkladstruct A { B b; } struct B { C c; } struct C { A a; }je chyba, protože každý typ
A,BaCzávisí na sobě.konec příkladu
U tříd je možné, aby dvě proměnné odkazovaly na stejný objekt, a proto operace s jednou proměnnou ovlivnit objekt odkazovaný druhou proměnnou. U struktur mají proměnné vlastní kopii dat (s výjimkou parametrů podle odkazu) a není možné, aby operace s jednou z nich ovlivnily druhý. Kromě toho, pokud není explicitně nullable (§8.3.12), není možné, aby hodnoty typu struktury byly null.
Poznámka: Pokud struktura obsahuje pole typu odkazu, lze obsah odkazovaného objektu změnit jinými operacemi. Hodnota samotného pole, tj. objektu, na který odkazuje, však nelze změnit prostřednictvím mutaci jiné hodnoty struktury. koncová poznámka
Příklad: S ohledem na následující:
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point a = new Point(10, 10); Point b = a; a.x = 100; Console.WriteLine(b.x); } }výstup je
10. Přiřazeníakbvytvoří kopii hodnoty, abproto není ovlivněno přiřazením ka.x. Kdyby bylPointmísto toho deklarován jako třída, výstup by byl100, protožeaabby odkazovaly na stejný objekt.konec příkladu
16.4.3 Dědičnost
Všechny typy struktur implicitně dědí z třídy System.ValueType, která následně dědí z třídy object. Deklarace struktury může určit seznam implementovaných rozhraní, ale není možné, aby deklarace struktury určila základní třídu.
Typy struktur nejsou nikdy abstraktní a vždy jsou implicitně zapečetěné. Modifikátory abstract a sealed proto nejsou povoleny v deklaraci struktury.
Vzhledem k tomu, že dědičnost není podporována pro struktury, deklarovaná přístupnost člena struktury nemůže být protected, private protectednebo protected internal.
Členy funkce ve struktuře nemohou být abstraktní nebo virtuální a override modifikátor je povolen pouze k přepsání metod zděděných z System.ValueType.
16.4.4 Přiřazení
Přiřazení proměnné typu struktury vytvoří kopii přiřazené hodnoty. Liší se od přiřazení k proměnné typu třídy, která kopíruje odkaz, ale nikoli objekt identifikovaný odkazem.
Podobně jako při přiřazení se při předání struktury jako hodnotový parametr nebo je vrácena jako výsledek funkčního člena vytvoří kopie struktury. Struktura může být předána odkazem na člen funkce pomocí parametru by-reference.
Je-li vlastnost nebo indexer struktury cílem přiřazení, výraz instance přidružený k vlastnosti nebo indexeru musí být klasifikován jako proměnná. Pokud je výraz instance klasifikován jako hodnota, dojde k chybě v době kompilace. Toto je podrobněji popsáno v §12.23.2.
16.4.5 Výchozí hodnoty
Jak je popsáno v §9.3, při vytváření se automaticky inicializuje několik druhů proměnných na jejich výchozí hodnotu. U proměnných typů tříd a jiných referenčních typů je nulltato výchozí hodnota . Vzhledem k tomu, že struktury jsou typy hodnot, které nemohou být null, výchozí hodnota struktury je hodnota vytvořená nastavením všech polí typu hodnoty na výchozí hodnotu a všechna pole odkazového typu na null.
Příklad: Odkazování na
Pointstrukturu deklarovanou výše, příkladPoint[] a = new Point[100];inicializuje každou
Pointz polí na hodnotu vytvořenou nastavenímxaypole na nulu.konec příkladu
Výchozí hodnota struktury odpovídá hodnotě vrácené výchozím konstruktorem struktury (§8.3.3). Na rozdíl od třídy není struktura povolena k deklaraci konstruktoru instance bez parametrů. Místo toho má každá struktura implicitně konstruktor instance bez parametrů, který vždy vrátí hodnotu, která je výsledkem nastavení všech polí na výchozí hodnoty.
Poznámka: Struktury by měly být navrženy tak, aby zvážily výchozí inicializační stav platného stavu. V příkladu
struct KeyValuePair { string key; string value; public KeyValuePair(string key, string value) { if (key == null || value == null) { throw new ArgumentException(); } this.key = key; this.value = value; } }konstruktor instance definovaný uživatelem chrání před
nullhodnotami pouze tam, kde je explicitně volána. V případech, kdy je proměnnáKeyValuePairpředmětem výchozí inicializace hodnot, budou polekeyavaluenulla struktura by měla být připravena na zpracování tohoto stavu.koncová poznámka
16.4.6 Boxing a unboxing
Hodnotu typu třídy lze převést na typ object nebo na typ rozhraní implementovaný třídou jednoduše tak, že v době kompilace považuje odkaz za jiný typ. Podobně je možné převést hodnotu typu object nebo hodnotu typu rozhraní zpět na typ třídy beze změny odkazu (v tomto případě je však nutná kontrola typu za běhu).
Vzhledem k tomu, že struktury nejsou odkazové typy, jsou tyto operace implementovány odlišně pro typy struktur. Pokud se hodnota typu struktury převede na určité referenční typy (jak je definováno v §10.2.9), dojde k operaci boxování. Podobně platí, že pokud je hodnota určitých referenčních typů (definovaná v §10.3.7) převedena zpět na typ struktury, provede se operace rozbalení. Klíčovým rozdílem od stejných operací u typů tříd je, že boxování a rozbalování kopíruje hodnotu struktury do boxované instance nebo z ní.
Poznámka: Po operaci boxingu nebo unboxingu se změny provedené v rozbaleném
structtedy neprojeví v boxovanémstruct. koncová poznámka
Další podrobnosti o balení a rozbalování naleznete v článcích §10.2.9 a §10.3.7.
16.4.7 Význam tohoto
Význam this struktury se liší od významu this třídy, jak je popsáno v §12.8.14. Pokud typ struktury přepíše virtuální metodu zděděnou z System.ValueType (například Equals, GetHashCode nebo ToString), vyvolání virtuální metody prostřednictvím instance typu struktury nezpůsobí boxování. To platí i v případě, že se struktura používá jako parametr typu a vyvolání probíhá prostřednictvím instance typu parametru.
Příklad:
struct Counter { int value; public override string ToString() { value++; return value.ToString(); } } class Program { static void Test<T>() where T : new() { T x = new T(); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); } static void Main() => Test<Counter>(); }Výstupem programu je:
1 2 3I když je špatným stylem, aby
ToStringměl vedlejší účinky, příklad ukazuje, že k boxování nedošlo při třech vyvoláníchx.ToString().konec příkladu
Podobně při přístupu k členu omezujícím typ parametru, je-li tento člen implementován v rámci typu hodnoty, nikdy nedochází k implicitnímu boxingu. Předpokládejme například, že rozhraní ICounter obsahuje metodu Increment, kterou lze použít k úpravě hodnoty. Pokud se ICounter používá jako omezení, implementace metody Increment je volána s odkazem na proměnnou, na které byla volána Increment, nikdy boxovaná kopie.
Příklad:
interface ICounter { void Increment(); } struct Counter : ICounter { int value; public override string ToString() => value.ToString(); void ICounter.Increment() => value++; } class Program { static void Test<T>() where T : ICounter, new() { T x = new T(); Console.WriteLine(x); x.Increment(); // Modify x Console.WriteLine(x); ((ICounter)x).Increment(); // Modify boxed copy of x Console.WriteLine(x); } static void Main() => Test<Counter>(); }První volání
Incrementmodifikuje hodnotu v proměnnéx. Toto není ekvivalentem druhého voláníIncrement, které upraví hodnotu v zabalené kopiix. Výstupem programu je tedy:0 1 1konec příkladu
16.4.8 Inicializátory polí
Jak je popsáno v §16.4.5, výchozí hodnota struktury se skládá z hodnoty, která je výsledkem nastavení všech polí typu hodnoty na výchozí hodnotu a všech polí odkazového typu na null. Z tohoto důvodu struktura nepovoluje deklarace polí instance, aby zahrnovaly inicializátory proměnných. Toto omezení platí jenom pro pole instancí. Statická pole struktury mohou obsahovat inicializátory proměnných.
Příklad: Následující:
struct Point { public int x = 1; // Error, initializer not permitted public int y = 1; // Error, initializer not permitted }je chybná, protože deklarace polí instance zahrnují inicializátory proměnných.
konec příkladu
Field_declaration deklarované přímo uvnitř struct_declaration, který má struct_modifierreadonly, musí mít field_modifierreadonly.
16.4.9 Konstruktory
Na rozdíl od třídy není struktura povolena k deklaraci konstruktoru instance bez parametrů. Místo toho má každá struktura implicitně konstruktor instance bez parametrů, který vždy vrátí hodnotu, která je výsledkem nastavení všech polí typu hodnoty na výchozí hodnotu a všechna pole odkazového typu na null (§8.3.3). Struktura může deklarovat konstruktory instance s parametry.
Příklad: S ohledem na následující:
struct Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point p1 = new Point(); Point p2 = new Point(0, 0); } }příkazy vytvoří
Pointsxayinicializováno na nulu.konec příkladu
Konstruktor instance struktury nesmí obsahovat inicializátor konstruktoru formuláře base(argument_list), kde argument_list je nepovinný.
Parametr this konstruktoru instance struktury odpovídá výstupnímu parametru typu struktury.
this musí být jednoznačně přiřazen (§9.4) v každém místě, kde se konstruktor vrátí. Podobně jej nelze číst (ani implicitně) v těle konstruktoru, dokud nebude s jistotou přiřazený.
Pokud konstruktor instance struktury určuje inicializátor konstruktoru, tento inicializátor je považován za určité přiřazení k tomu, které nastane před tělem konstruktoru. Proto samotné tělo nemá žádné inicializační požadavky.
Příklad: Zvažte implementaci konstruktoru instance níže:
struct Point { int x, y; public int X { set { x = value; } } public int Y { set { y = value; } } public Point(int x, int y) { X = x; // error, this is not yet definitely assigned Y = y; // error, this is not yet definitely assigned } }Nelze volat žádný člen funkce instance (včetně přístupových objektů sady pro vlastnosti
XaY) dokud nebudou jednoznačně přiřazena všechna pole struktury, která je vytvořena. Mějte však na paměti, že pokud byPointbyla třída místo struktury, implementace konstruktoru instanční by byla povolena. Existuje jedna výjimka, která zahrnuje automaticky implementované vlastnosti (§15.7.4). Určitá pravidla přiřazení (§12.23.2) výslovně vyloučila přiřazení k automatické vlastnosti typu struktury v rámci konstruktoru instance tohoto typu struktury: takové přiřazení je považováno za určité přiřazení skrytého záložního pole automatické vlastnosti. Proto je povoleno následující:struct Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; // allowed, definitely assigns backing field Y = y; // allowed, definitely assigns backing field } }konec příkladu]
16.4.10 Statické konstruktory
Statické konstruktory pro struktury se řídí většinou stejných pravidel jako u tříd. Spuštění statického konstruktoru pro typ struktury je aktivováno první z následujících událostí v rámci domény aplikace:
- Na statický člen typu struktury se odkazuje.
- Explicitně deklarovaný konstruktor strukturovaného typu je volán.
Poznámka: Vytvoření výchozích hodnot (§16.4.5) typů struktury neaktivuje statický konstruktor. (Příkladem je počáteční hodnota prvků v poli.) koncová poznámka
16.4.11 Vlastnosti
Deklarace vlastnosti (§15.7.1) pro vlastnost instance v deklarace struktury může obsahovat modifikátor vlastnostireadonly. Statická vlastnost však nesmí obsahovat tento modifikátor.
Jedná se o chybu v době kompilace, pokud se pokusíte změnit stav proměnné struktury instance prostřednictvím vlastnosti readonly deklarované v této struktuře.
Jedná se o chybu v době kompilace, pokud má automaticky implementovaná vlastnost modifikátor readonly a rovněž přístupový člen set.
Jedná se o chybu v době kompilace pro automaticky implementovanou vlastnost ve readonly struktuře, která má přístupový objekt set .
Automaticky implementovaná vlastnost deklarovaná uvnitř readonly struktury nemusí mít readonly modifikátor, protože jeho get příslušenství je implicitně považováno za jen pro čtení.
Jedná se o chybu v době kompilace mít readonly modifikátor u samotné vlastnosti i u kterékoliv z jejich get a set přístupových metod.
Jedná se o chybu v době kompilace, kdy vlastnost má u všech jeho přístupových objektů modifikátor jen pro čtení.
Poznámka: Chcete-li chybu opravit, přesuňte modifikátor z přístupových objektů do samotné vlastnosti. koncová poznámka
Pro výraz přistupování vlastností: s.P
- Jedná se o chybu v době kompilace, pokud
s.Pvyvolá přístupový objektMsady typuTpři procesu v §12.6.6.1 by vytvořil dočasnou kopiis. - Pokud
s.Pvyvolá přístupové objekty get typuT, proces v §12.6.6.1 se následuje, včetně vytvoření dočasné kopiesv případě potřeby.
Automaticky implementované vlastnosti (§15.7.4) používají skrytá doprovodná data, která jsou přístupná pouze přistupovým metodám k vlastnostem.
Poznámka: Toto omezení přístupu znamená, že konstruktory v strukturách obsahujících automaticky implementované vlastnosti často potřebují explicitní inicializátor konstruktoru, kde by jinak nepotřebují jeden, aby splňovaly požadavek všech polí, která jsou jednoznačně přiřazena před vyvoláním jakéhokoli člena funkce nebo vrátí konstruktor. koncová poznámka
16.4.12 Metody
Method_declaration (§15.6.1) pro instanční metodu v struct_declaration může obsahovat method_modifierreadonly. Statická metoda však nesmí tento modifikátor obsahovat.
Jedná se o chybu v době kompilace při pokusu o změnu stavu proměnné struktury instance prostřednictvím metody readonly deklarované v této struktuře.
I když metoda jen pro čtení může volat sesterskou, nesesterskou metodu, nebo vlastnost nebo indexer get accessor, výsledkem je vytvoření implicitní kopie this jako obranné opatření.
Metoda jen pro čtení může volat vlastnost na stejné stejné nebo indexer nastavit přístupový objekt, který je jen pro čtení. Pokud přístupový objekt sesterského člena není explicitně nebo implicitně pouze pro čtení, dojde k chybě kompilace.
Všechny deklarace částečné metody musí mít modifikátor, nebo žádná z nich ho nesmí mít.
16.4.13 Indexátory
Indexovač_deklarace (§15.9) pro instanční indexovač ve struct_declaration může obsahovat indexer_modifierreadonly.
Jedná se o chybu v době kompilace při pokusu o změnu stavu proměnné struktury instance prostřednictvím indexeru jen pro čtení deklarovaného v této struktuře.
Jedná se o chybu v době kompilace, pokud je modifikátor readonly umístěn na samotném indexeru nebo na kterékoli z jeho přístupových metod get či set.
Jedná se o chybu v době kompilace, kdy indexer má u všech jeho přístupových objektů modifikátor jen pro čtení.
Poznámka: Chcete-li chybu opravit, přesuňte modifikátor z přístupových objektů do samotného indexeru. koncová poznámka
16.4.14 Události
Deklarace události (§15.8.1) pro instanci, ne jako pole, ve struct_declaration může obsahovat event_modifier. Statická událost však nesmí obsahovat tento modifikátor.
16.4.15 Bezpečné omezení kontextu
16.4.15.1 Obecné
V době kompilace je každý výraz přidružený k kontextu, kde tato instance a všechna její pole mohou být bezpečně přístupná, jeho bezpečný kontext. Bezpečný kontext je ten, ve kterém je výraz bezpečně uzavřen a kam může hodnota bezpečně uniknout.
Libovolný výraz, jehož typ kompilace není ref strukturou, má bezpečný kontext kontextu volajícího kontextu.
Výraz default pro libovolný typ má bezpečný kontext kontextu volajícího.
Pro jakýkoli nevýchozí výraz, jehož typ při kompilaci je ref struct, je bezpečný kontext definován v následujících částech.
Záznamy bezpečného kontextu, do kterých je možné zkopírovat kontextovou hodnotu. Při přiřazení z výrazu E1 s bezpečným kontextem S1k výrazu E2 s bezpečným kontextem S2se jedná o chybu, pokud S2 je širší kontext než S1.
Existují tři různé hodnoty bezpečného kontextu, stejné jako hodnoty kontextu ref-safe-context definované pro referenční proměnné (§9.7.2): blok deklarace, člen funkce a kontext volajícího. Bezpečný kontext výrazu omezuje jeho použití následujícím způsobem:
- V případě návratového prohlášení
return e1, musí být bezpečný kontexte1v kontextu volajícího. - Pro přiřazení
e1 = e2musí být bezpečný kontexte2alespoň tak široký, jako je bezpečný kontexte1.
Pro vyvolání metody, pokud existuje argument ref nebo out typu ref struct (včetně příjemce, pokud není typu readonly), s bezpečným kontextem S1, pak žádný argument (včetně příjemce) nesmí mít užší bezpečný kontext než S1.
16.4.15.2 Kontext bezpečného parametru
Parametr struktury typu ref, včetně parametru metody instance this, má bezpečný kontext volajícího.
Bezpečný kontext pro místní proměnné
Místní proměnná typu ref struct má bezpečný kontext následovně:
- Pokud je proměnná iterační proměnnou
foreachsmyčky, je bezpečný kontext proměnné stejný jako bezpečný kontext výrazuforeachsmyčky. - V opačném případě, pokud deklarace proměnné má inicializátor, pak je bezpečný kontext proměnné stejný jako bezpečný kontext tohoto inicializátoru.
- V opačném případě je proměnná neinicializována v okamžiku deklarace a má bezpečný kontext kontextu volajícího.
16.4.15.4 Kontext bezpečného pole
Odkaz na pole e.F, kde typ F je typ ref struktury, má bezpečný kontext, který je stejný jako bezpečný kontext e.
16.4.15.5 – operátory
Použití uživatelem definovaného operátoru se považuje za metodu vyvolání (§16.4.15.6).
Pro operátor, který poskytuje hodnotu, například e1 + e2 nebo c ? e1 : e2, bezpečný kontext výsledku je nejužší kontext mezi bezpečnými kontexty operandů operátoru. V důsledku toho je pro unární operátor, který poskytuje hodnotu, například +e, bezpečný kontext výsledku stejný jako bezpečný kontext operandu.
Poznámka: První operand podmíněného operátoru je
bool, takže jeho bezpečný kontext je kontext volajícího. Z toho vyplývá, že výsledný bezpečný kontext je nejužším bezpečným kontextem druhého a třetího operandu. koncová poznámka
16.4.15.6 Metoda a vyvolání vlastnosti
Hodnota, která je výsledkem vyvolání e1.M(e2, ...) metody nebo vyvolání e.P vlastnosti, má bezpečný kontext nejmenších z následujících kontextů:
- kontext volajícího.
- Bezpečný kontext všech výrazů argumentů (včetně příjemce).
Vyvolání vlastnosti (nebo getset) se považuje za metodu vyvolání základní metody výše uvedenými pravidly.
16.4.15.7 stackalloc
Výsledkem výrazu stackalloc je bezpečný kontext člena funkce.
16.4.15.8 Vyvolání konstruktoru
Výraz new , který vyvolá konstruktor, dodržuje stejná pravidla jako volání metody, která je považována za vrácení typu vytvořeného.
Navíc je bezpečný kontext nejmenší z bezpečných kontextů všech argumentů a operandů všech výrazů inicializátoru objektu rekurzivně, pokud je přítomen nějaký inicializátor.
Poznámka: Tato pravidla spoléhají na to, že
Span<T>nemá konstruktor následující podoby:public Span<T>(ref T p)Takový konstruktor vytváří instance
Span<T>používané jako pole nerozlišující odrefpole. Bezpečnostní pravidla popsaná v tomto dokumentu závisí narefpolích, která nejsou platným konstruktorem v jazyce C# nebo .NET. koncová poznámka
ECMA C# draft specification