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.
10.1 Obecné
Převod způsobí, že se výraz převede na určitý typ nebo se s ním zachází. V prvním případě může převod zahrnovat změnu v reprezentaci. Převody mohou být implicitní nebo explicitní a určuje, zda je vyžadováno explicitní přetypování.
Příklad: Například převod z typu
intna typlongje implicitní, takže výrazy typuintmohou být implicitně považovány za typlong. Opačný převod typu na typlongintje explicitní a proto je vyžadován explicitní přetypování.int a = 123; long b = a; // implicit conversion from int to long int c = (int) b; // explicit conversion from long to intkonec příkladu
Některé převody jsou definovány jazykem. Programy mohou rovněž definovat vlastní převody (§10.5).
Některé převody v jazyce jsou definovány z výrazů na typy, jiné z typů na typy. Převod z typu se vztahuje na všechny výrazy, které tento typ mají.
Příklad:
enum Color { Red, Blue, Green } // The expression 0 converts implicitly to enum types Color c0 = 0; // Other int expressions need explicit conversion Color c1 = (Color)1; // Conversion from null expression (no type) to string string x = null; // Conversion from lambda expression to delegate type Func<int, int> square = x => x * x;konec příkladu
10.2 Implicitní převody
10.2.1 Obecné
Následující převody jsou klasifikovány jako implicitní převody:
- Převody identit (§10.2.2)
- Implicitní číselné převody (§10.2.3)
- Implicitní převody výčtů (§10.2.4)
- Implicitní interpolované převody řetězců (§10.2.5)
- Implicitní převody odkazů (§10.2.8)
- Převody krabic (§10.2.9)
- Implicitní dynamické převody (§10.2.10)
- Implicitní převody parametrů typu (§10.2.12)
- Implicitní převody konstantních výrazů (§10.2.11)
- Implicitní převody definované uživatelem (včetně zrušených) (§10.2.14)
- Anonymní převody funkcí (§10.2.15)
- Převody skupin metod (§10.2.15)
- Převody literálů null (§10.2.7)
- Implicitní převody s možnou hodnotou null (§10.2.6)
- Implicitní převody řazené kolekce členů (§10.2.13)
- Výchozí převody literálů (§10.2.16)
- Implicitní převody vyvolání (§10.2.17)
Implicitní převody mohou nastat v různých situacích, včetně vyvolání členů funkce (§12.6.6), přetypování výrazů (§12.9.8) a přiřazení (§12.23).
Předem definované implicitní převody vždy proběhnou úspěšně a nikdy nezpůsobí vyvolání výjimek.
Poznámka: Správně navržené uživatelem definované implicitní převody by měly mít také tyto vlastnosti. koncová poznámka
Pro účely převodu jsou typy object a dynamic identity konvertibilní (§10.2.2).
Dynamické převody (§10.2.10) se však vztahují pouze na výrazy typu dynamic (§8.2.4).
10.2.2 Převod identity
Převod identity se převede z libovolného typu na stejný typ nebo typ, který je ekvivalentní za běhu. Jedním z důvodů, proč tento převod existuje, je tak, že typ T nebo výraz typu T lze říci, že se má převést na T sebe. Existují následující převody identit:
- Mezi
TaT, pro jakýkoliv typT. - Mezi
TaT?pro libovolný typ odkazuT. - Mezi
objectadynamic. - Mezi všemi typy řazené kolekce členů se stejnou a odpovídající konstruovaný
ValueTuple<...>typ, pokud existuje převod identity mezi každou dvojicí odpovídajících typů prvků. - Mezi typy vytvořenými ze stejného obecného typu, kde existuje převod identity mezi každým odpovídajícím argumentem typu.
Příklad: Následující příklad znázorňuje rekurzivní povahu třetího pravidla:
(int a , string b) t1 = (1, "two"); (int c, string d) t2 = (3, "four"); // Identity conversions exist between // the types of t1, t2, and t3. var t3 = (5, "six"); t3 = t2; t2 = t1; var t4 = (t1, 7); var t5 = (t2, 8); // Identity conversions exist between // the types of t4, t5, and t6. var t6 =((8, "eight"), 9); t6 = t5; t5 = t4;Typy řazených kolekcíčlenůch
t1t2t3intstringTypy elementů řazené kolekce členů mohou být samy o sobě, jako vt4,t5at6. Mezi jednotlivými dvojicemi odpovídajících typů prvků, včetně vnořených řazených kolekcí členů, existuje převod identity mezi typy řazenýcht4kolekcí členů at5t6.konec příkladu
Všechny převody identit jsou symetrické. Pokud existuje převod identity z T₁ do T₂, pak existuje převod identity z T₂ do T₁. Dva typy jsou konvertibilní identity, pokud existuje převod identity mezi dvěma typy.
Ve většiněpřípadůch Vzhledem k tomu, že operace s plovoucí desetinnou čárkou mohou být prováděny s vyšší přesností, než je stanoveno jejich typem (§8.3.7), může přiřazení výsledků vést ke ztrátě přesnosti a explicitní přetypování je zaručeno snížení přesnosti na to, co je předepsáno typem (§12.9.8).
10.2.3 Implicitní číselné převody
Implicitní číselné převody jsou:
- Od
sbytedo , ,shortint,long, ,floatnebodouble.decimal - Od
bytedo ,short, ,ushort, ,int,uintlongulongfloatnebo .doubledecimal - Od
shortdo ,int,long,float, nebodouble.decimal - Od
ushortdo , ,int,uint,long, ,ulong,floatnebodouble.decimal - Od
intdolong,float,doublenebodecimal. - Od
uintdo ,long,ulong,float, nebodouble.decimal - Od
longdofloat,doublenebodecimal. - Od
ulongdofloat,doublenebodecimal. - Od
chardo ,ushort, ,int,uint, ,long,ulong,float, nebodouble.decimal - Od
floatdodouble.
Převody z int, , uintlongnebo ulong z float a z long nebo ulong na double mohou způsobit ztrátu přesnosti, ale nikdy nezpůsobí ztrátu velikosti. Ostatní implicitní číselné převody nikdy neztratí žádné informace.
Neexistují žádné předdefinované implicitní převody na char typ, takže hodnoty ostatních integrálních typů se automaticky nepřevádějí na char typ.
10.2.4 Implicitní převody výčtu
Implicitní převod výčtu umožňuje constant_expression (§12.25) s jakýmkoli typem celého čísla a hodnotou nula, která se má převést na jakýkoli enum_type a na jakýkoli nullable_value_type jehož podkladovým typem je enum_type. V druhém případě je převod vyhodnocen převodem na podkladovou enum_type a zabalením výsledku (§8.3.12).
10.2.5 Implicitní interpolované převody řetězců
Implicitní interpolovaný převod řetězců umožňuje převést interpolated_string_expression (§12.8.3) na System.IFormattable nebo System.FormattableString (která implementuje System.IFormattable).
Při použití tohoto převodu se řetězcová hodnota nevytváření z interpolovaného řetězce. Místo toho se vytvoří instance System.FormattableString , jak je dále popsáno v §12.8.3.
10.2.6 Implicitní převody s možnou hodnotou null
Implicitní převody s možnou hodnotou null jsou převody s možnou hodnotou null (§10.6.1) odvozené z implicitních předdefinovaných převodů.
10.2.7 Převody literálů null
Implicitní převod existuje z literálu null na jakýkoli typ odkazu nebo typ hodnoty null. Tento převod vytvoří nulový odkaz, pokud je cílovým typem odkaz nebo hodnota null (§8.3.12) daného typu hodnoty s možnou hodnotou null.
10.2.8 Implicitní převody odkazů
Implicitní převody odkazů jsou:
- Z libovolného reference_type do
objectadynamic. - Z jakéhokoli do libovolného
S, je odvozeno odT. - Z libovolného , poskytnuté
Simplementuje . - Z jakéhokoli do libovolného
S, je odvozeno odT. -
s typem
SelementuSᵢs typemTelementu jsou splněny všechny následující podmínky:-
SaTliší se pouze v typu prvku. Jinými slovy,SaTmají stejný počet dimenzí. - Implicitní převod odkazu existuje z
SᵢdoTᵢ.
-
- Z jednorozměrného typu
S[]pole naSystem.Collections.Generic.IList<T>,System.Collections.Generic.IReadOnlyList<T>a jejich základní rozhraní za předpokladu, že existuje implicitní identita nebo odkaz převodu zST. - Z libovolného array_type do
System.Arraya rozhraní, která implementuje. - Z libovolného delegate_type do
System.Delegatea rozhraní, která implementuje. - Od literálu s hodnotou null (§6.4.5.7) až po libovolný typ odkazu.
- Z libovolného reference_type na , pokud má implicitní identitu nebo odkaz na
TaT₀má převod identity naT₀. - Z jakéhokoli reference_type na rozhraní nebo typ
Tdelegáta, pokud má implicitní převod identity nebo odkazu na rozhraní nebo typT₀delegáta aT₀je variance-sklápěcí (§19.2.3.3) naT. - Implicitní převody zahrnující parametry typu, které jsou známé jako odkazové typy. Další podrobnosti o implicitních převodech zahrnujících parametry typu najdete v §10.2.12 .
Implicitní převody odkazů jsou tyto převody mezi reference_types, které lze prokázat, že jsou vždy úspěšné, a proto nevyžadují žádné kontroly za běhu.
Převody odkazů, implicitní nebo explicitní, nikdy nemění referenční identitu převedeného objektu.
Poznámka: Jinými slovy, zatímco převod odkazu může změnit typ odkazu, nikdy nezmění typ nebo hodnotu objektu, na který se odkazuje. koncová poznámka
10.2.9 Převody krabic
Převod boxingu umožňuje implicitně převést value_type na reference_type. Existují následující převody boxingu:
- Z libovolného value_type na typ
object. - Z libovolného value_type na typ
System.ValueType. - Z libovolného enum_type na typ
System.Enum. - Z libovolného non_nullable_value_type do libovolnéhointerface_type implementovaného non_nullable_value_type.
- Z jakéhokoli non_nullable_value_type na jakýkoli interface_type
Itak, že existuje převod boxingu z non_nullable_value_type na jiný interface_typeI₀aI₀má převod identity na .I - Z jakéhokoli non_nullable_value_type na jakýkoli interface_type
Itakový, že existuje převod krabic z non_nullable_value_type na jiný interface_typeI₀aI₀je variance-sklápěcí (§19.2.3.3) naI. - Z libovolného nullable_value_type do libovolného reference_type, kde existuje převod krabicového převodu z podkladového typu nullable_value_type na reference_type.
- Z parametru typu, o který není známo, že jde o odkazový typ, aby převod byl povolen §10.2.12.
Boxing a value of a non-nullable-value-type is alokace instance objektu a kopírování hodnoty do této instance.
Zaboxování hodnoty typu nullable_value_type vygeneruje null referenci, pokud je to null hodnota (HasValue je false), nebo výsledek rozbalení a zaboxování základní hodnoty v opačném případě.
Poznámka: Proces balení lze představit z hlediska existence boxovací třídy pro každý typ hodnoty. Představte si například implementaci
struct SrozhraníIs boxovací třídou s názvemS_Boxing.interface I { void M(); } struct S : I { public void M() { ... } } sealed class S_Boxing : I { S value; public S_Boxing(S value) { this.value = value; } public void M() { value.M(); } }Boxing a value
vof typeSnow contains of executing the expressionnew S_Boxing(v)and returning the výsledný instance as a value of the target type of the conversion. Proto příkazyS s = new S(); object box = s;lze považovat za podobné:
S s = new S(); object box = new S_Boxing(s);Představovaný typ boxingu popsaný výše ve skutečnosti neexistuje. Místo toho má boxovaná hodnota typu
StypSmodulu runtime a kontrolu typu modulu runtime pomocíisoperátoru s typem hodnoty jako pravý operand testuje, zda je levý operand zadaná verze pravého operandu. Příklad:int i = 123; object box = i; if (box is int) { Console.Write("Box contains an int"); }vypíše následující výstup:
Box contains an intPřevod boxingu znamená vytvoření kopie hodnoty, která se boxuje. To se liší od převodu reference_type na typ
object, ve kterém hodnota nadále odkazuje na stejnou instanci a jednoduše je považována za méně odvozený typobject. Například následující:struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { void M() { Point p = new Point(10, 10); object box = p; p.x = 20; Console.Write(((Point)box).x); } }zobrazí výstup hodnoty 10 v konzole, protože implicitní operace boxingu, která nastane v přiřazení
pkboxpříčinám kopírování hodnotyp. BylaPointdeklarována místoclasstoho, hodnota 20 by byla výstupem, protožepbyboxodkazovala na stejnou instanci.Analogie třídy boxingu by neměla být použita jako více než užitečný nástroj pro znázornění toho, jak boxování funguje koncepčně. Mezi chováním popsaným v této specifikaci a chováním, které by vedlo k implementaci boxingu přesně tímto způsobem, existuje mnoho drobných rozdílů.
koncová poznámka
10.2.10 Implicitní dynamické převody
Implicitní dynamický převod existuje z výrazu typu dynamického na jakýkoli typ T. Převod je dynamicky vázán §12.3.3, což znamená, že implicitní převod bude vyhledán za běhu od typu běhu výrazu na T. Pokud se nenajde žádný převod, vyvolá se výjimka za běhu.
Tento implicitní převod zdánlivě porušuje radu na začátku §10.2 , že implicitní převod by nikdy neměl způsobit výjimku. Nejedná se však o samotný převod, ale o nalezení převodu, který způsobuje výjimku. Riziko výjimek za běhu je spojeno s používáním dynamické vazby. Pokud dynamická vazba převodu není žádoucí, lze výraz nejprve převést na objecta potom na požadovaný typ.
Příklad: Následující příklad znázorňuje implicitní dynamické převody:
object o = "object"; dynamic d = "dynamic"; string s1 = o; // Fails at compile-time – no conversion exists string s2 = d; // Compiles and succeeds at run-time int i = d; // Compiles but fails at run-time – no conversion existsPřiřazení k
s2implicitnímidynamickým převodům a jejich použití, kdy je vazba operací pozastavena do doby běhu. Za běhu se implicitní převody hledají z typudruntime (string) na cílový typ. Převod je nalezen,stringale nikoliintna .konec příkladu
10.2.11 Implicitní převody konstantních výrazů
Převod implicitního konstantního výrazu umožňuje následující převody:
-
Typ constant_expression (§12.25)
intlze převést na typsbyte,byte, ,short,ushortuintneboulong, za předpokladu, že hodnota constant_expression je v rozsahu cílového typu. - Constant_expression typu
longlze převést na typulongza předpokladu, že hodnota constant_expression není záporná.
10.2.12 Implicitní převody zahrnující parametry typu
, o kterých je známo, že se jedná o referenční typ (T), existují následující implicitní převody odkazů (§10.2.8):
- Od
Tdo své účinné základní třídyC, odTdo jakékoli základní třídyC, a odTdo libovolného rozhraní implementovanéhoC. - Od
Tinterface_typevIefektivní sadě rozhraní a zTlibovolného základníhoTrozhraní . - Od
Tparametru typuU, kterýTzávisí naU(§15.2.5).Poznámka: Vzhledem k tomu
T, že je známo, že jde o typ odkazu, v rámci oboruTbude typUběhu vždy odkazový typ, i kdyžUnení známo, že se jedná o typ odkazu v době kompilace. koncová poznámka - Z literálu null (§6.4.5.7) do T.
, o němž neníTjde o odkazový typ §15.2.5, se při kompilaci považují následující převody zahrnující převody do balení (T). Pokud je to typ hodnoty za běhu T , převod se spustí jako převod boxingu. Pokud se jedná o referenční typ, provede se převod za běhu T jako implicitní převod odkazu nebo převod identity.
- Od
Tdo své účinné základní třídyC, odTdo jakékoli základní třídyC, a odTdo libovolného rozhraní implementovanéhoC.Poznámka:
Cbude jedním z typůSystem.Object,System.ValueTypeneboSystem.Enum(jinakTby bylo známo, že se jednat o odkazový typ). koncová poznámka - Od
Tinterface_typevIefektivní sadě rozhraní a zTlibovolného základníhoTrozhraní .
U type_parameterT, o kterých není známo, že se jedná o odkazový typ, existuje implicitní převod ze T zadaného U parametru T typu závisí na U.
T Pokud je to typ hodnoty a U jedná se o referenční typ, provede se převod jako převod boxingu. Pokud jsou oba T typy U hodnot za běhu, pak T a U jsou nutně stejného typu a neprovádí se žádný převod. V době běhu je-li T referenčním typem, U pak je nutně také referenčním typem a převod se provede jako implicitní převod odkazu nebo převod identity (§15.2.5).
Pro daný parametr Ttypu existují následující další implicitní převody:
- Od
Ttypu odkazuS, pokud má implicitní převod na typS₀odkazu aS₀má převod identity naS. Za běhu se převod provede stejným způsobem jako převod naS₀. - Typ
TrozhraníI, pokud má implicitní převod na typI₀rozhraní aI₀je variance-konvertibilní naI(§19.2.3.3). Pokud je to typ hodnoty za běhuT, převod se spustí jako převod boxingu. V opačném případě se převod provede jako implicitní převod odkazu nebo převod identity.
Ve všech případech pravidla zajišťují, že se převod provede jako převod boxingu, pouze pokud je převod za běhu převodu z typu hodnoty na odkazový typ.
10.2.13 Implicitní převody řazené kolekce členů
Implicitní převod existuje z výrazu E řazené kolekce členů na typ T řazené kolekce členů, pokud E má stejnýrit jako T a implicitní převod existuje z každého prvku E do odpovídajícího typu elementu v T. Převod se provádí vytvořením instance odpovídajícího TSystem.ValueTuple<...> typu a inicializací každého z jeho polí v pořadí odleva doprava vyhodnocením odpovídajícího výrazu elementu Eřazené kolekce členů , převodem na odpovídající typ elementu T pomocí nalezen implicitního převodu a inicializací pole s výsledkem.
Pokud název elementu ve výrazu řazené kolekce členů neodpovídá odpovídajícímu názvu elementu v typu řazené kolekce členů, musí být vydáno upozornění.
Příklad:
(int, string) t1 = (1, "One"); (byte, string) t2 = (2, null); (int, string) t3 = (null, null); // Error: No conversion (int i, string s) t4 = (i: 4, "Four"); (int i, string) t5 = (x: 5, s: "Five"); // Warning: Names are ignored
t1Deklarace ,t2t4at5jsou všechny platné, protože implicitní převody existují z výrazů elementů na odpovídající typy elementů.t3Deklarace je neplatná, protože neexistuje žádný převod znullintna .t5Deklarace způsobuje upozornění, protože názvy prvků ve výrazu řazené kolekce členů se liší od těch v typu řazené kolekce členů.konec příkladu
10.2.14 Uživatelem definované implicitní převody
Implicitní převod definovaný uživatelem se skládá z volitelného standardního implicitního převodu následovaného spuštěním operátoru implicitního převodu definovaného uživatelem a dalšího volitelného standardního implicitního převodu. Přesná pravidla pro vyhodnocení implicitních převodů definovaných uživatelem jsou popsána v §10.5.4.
10.2.15 Převody anonymních funkcí a převody skupin metod
Anonymní funkce a skupiny metod nemají vlastní typy, ale mohou být implicitně převedeny na typy delegátů. Některé výrazy lambda mohou být navíc implicitně převedeny na typy stromu výrazů. Anonymní převody funkcí jsou podrobněji popsány v §10.7 a převody skupin metod v §10.8.
10.2.16 Výchozí převody literálů
Implicitní převod existuje z default_literal (§12.8.21) na jakýkoli typ. Tento převod vytvoří výchozí hodnotu (§9.3) odvozeného typu.
10.2.17 Implicitní vyvolání převodů
Zatímco vyvolání výrazů nemá typ, mohou být implicitně převedeny na jakýkoli typ.
10.2.18 Převod výrazu Switch
Existuje implicitní převod z switch_expression (§12.11) na každý typ T , pro který existuje implicitní převod z každého switch_expression_armswitch_expression_arm_expression na T.
10.3 Explicitní převody
10.3.1 Obecné
Následující převody jsou klasifikovány jako explicitní převody:
- Všechny implicitní převody (§10.2)
- Explicitní číselné převody (§10.3.2)
- Explicitní převody výčtů (§10.3.3)
- Explicitní převody s možnou hodnotou null (§10.3.4)
- Explicitní převody řazené kolekce členů (§10.3.6)
- Explicitní převody odkazů (§10.3.5)
- Explicitní převody rozhraní
- Zrušení převodů (§10.3.7)
- Explicitní převody parametrů typu (§10.3.8)
- Explicitní převody definované uživatelem (§10.3.9)
Explicitní převody mohou nastat ve výrazech přetypování (§12.9.8).
Sada explicitních převodů zahrnuje všechny implicitní převody.
Poznámka: To například umožňuje použít explicitní přetypování, pokud existuje implicitní převod identity, aby bylo možné vynutit výběr konkrétního přetížení metody. koncová poznámka
Explicitní převody, které nejsou implicitními převody, jsou převody, které nelze vždy ověřit jako úspěšné, převody, které jsou známy pravděpodobně ke ztrátě informací, a převody napříč doménami typů dostatečně odlišné, aby si zaslouží explicitní zápis.
10.3.2 Explicitní číselné převody
Explicitní číselné převody jsou převody z numeric_type na jiný numeric_type , pro které implicitní číselný převod (§10.2.3) ještě neexistuje:
- Od
sbytedo ,byte,ushort,uint, neboulong.char - Od
bytedosbytenebochar. - Od
shortdo , ,sbytebyte,ushort, ,uintneboulong.char - Od
ushortdosbyte,byte,shortnebochar. - Od
intdo , ,sbyte,byte,short, ,ushort,uintneboulong.char - Od
uintdo , ,sbytebyte,short, ,ushortneboint.char - Od
longdo ,sbyte, ,byte,short, ,ushort,int,uint, neboulong.char - Od
ulongdo ,sbyte, ,byte,short, ,ushort,int,uint, nebolong.char - Od
chardosbyte,byteneboshort. - Od
floatdosbyte,byte, ,short, ,ushort,int,uintlongulongchar, , nebo .decimal - Od , , ,
double, ,sbyte,byte,short,ushortint,uint,long, neboulong.charfloatdecimal - Od , , ,
decimal, ,sbyte,byte,short,ushortint,uint,long, neboulong.charfloatdouble
Vzhledem k tomu, že explicitní převody zahrnují všechny implicitní a explicitní číselné převody, je vždy možné převést z libovolného numeric_type na jakýkoli jiný numeric_type pomocí výrazu přetypování (§12.9.8).
Explicitní číselné převody pravděpodobně ztratí informace nebo mohou způsobit vyvolání výjimek. Explicitní číselný převod se zpracuje takto:
- Při převodu celočíselného typu na jiný celočíselný typ závisí zpracování na kontextu kontroly přetečení (§12.8.20), ve kterém probíhá převod:
-
checkedV kontextu bude převod úspěšný, pokud je hodnota zdrojového operandu v rozsahu cílového typu, ale vyvoláSystem.OverflowExceptionchybu, pokud je hodnota zdrojového operandu mimo rozsah cílového typu. -
uncheckedV kontextu převod vždy proběhne úspěšně a pokračuje následujícím způsobem.- Pokud je zdrojový typ větší než cílový typ, je zdrojová hodnota zkrácena zrušením jeho "extra" nejvýznamnějších bitů. Výsledek se pak považuje za hodnotu cílového typu.
- Pokud je typ zdroje stejná jako cílový typ, je zdrojová hodnota považována za hodnotu cílového typu.
-
- Při převodu z
decimalna celočíselný typ se zdrojová hodnota zaokrouhlí na nulu na nejbližší celočíselnou hodnotu a tato integrální hodnota se stane výsledkem převodu. Pokud je výsledná integrální hodnota mimo rozsah cílového typu,System.OverflowExceptionvyvolá se hodnota. - Při převodu z
floatceločíselnéhodoubletypu závisí zpracování na kontextu kontroly přetečení (§12.8.20), ve kterém probíhá převod:- V kontrolovaném kontextu bude převod pokračovat následujícím způsobem:
- Pokud je hodnota operandu NaN nebo nekonečná,
System.OverflowExceptionvyvolá se hodnota. - V opačném případě se zdrojový operand zaokrouhlí na nulu na nejbližší celočíselnou hodnotu. Pokud je tato integrální hodnota v rozsahu cílového typu, je tato hodnota výsledkem převodu.
-
System.OverflowExceptionV opačném případě je vyvolán.
- Pokud je hodnota operandu NaN nebo nekonečná,
- V nezaškrtnutém kontextu bude převod vždy úspěšný a bude pokračovat následujícím způsobem.
- Pokud je hodnota operandu NaN nebo nekonečná, je výsledkem převodu nezadaná hodnota cílového typu.
- V opačném případě se zdrojový operand zaokrouhlí na nulu na nejbližší celočíselnou hodnotu. Pokud je tato integrální hodnota v rozsahu cílového typu, je tato hodnota výsledkem převodu.
- V opačném případě je výsledkem převodu nezadaná hodnota cílového typu.
- V kontrolovaném kontextu bude převod pokračovat následujícím způsobem:
- Při převodu z
doublenafloatdoublese hodnota zaokrouhlí na nejbližšífloathodnotu.doublePokud je hodnota příliš malá, aby představovala jako ,floatvýsledek se změní na nulu se stejným znaménkem jako hodnota. Pokud je velikostdoublehodnoty příliš velká, aby představovala jako ,floatvýsledek se stane nekonečnem se stejným znaménkem jako hodnota.doublePokud je hodnota NaN, výsledek je také NaN. - Při převodu ze
floatzdroje nebodoublenadecimalje zdrojová hodnota převedena nadecimalreprezentaci a v případě potřeby se zaokrouhlí na nejbližší číslo (§8.3.8).- Pokud je zdrojová hodnota příliš malá, aby představovala jako
decimal, výsledek se změní na nulu, zachová se znaménko původní hodnoty, pokuddecimalpodporuje podepsané nulové hodnoty. - Pokud je velikost zdrojové hodnoty příliš velká, aby reprezentovala jako
decimalhodnotu , nebo je tato hodnota nekonečno, je výsledkem nekonečno zachování znaménka původní hodnoty, pokud desítkové vyjádření podporuje nefinity; jinak je vyvolána výjimka System.OverflowException. - Pokud je zdrojová hodnota NaN, výsledek je NaN, pokud desítková reprezentace podporuje sítě NaN; Jinak je vyvolán výjimka System.OverflowException.
- Pokud je zdrojová hodnota příliš malá, aby představovala jako
- Pro převod z
decimalfloatnebodoublejedecimalhodnota zaokrouhlená na nejbližšídoublenebofloathodnotu. Pokud je velikost zdrojové hodnoty příliš velká, aby představovala v cílovém typu, nebo je tato hodnota nekonečno, výsledek je nekonečno zachovácí znaménko původní hodnoty. Pokud je zdrojová hodnota NaN, výsledek je NaN. I když tento převod může ztratit přesnost, nikdy nezpůsobí vyvolání výjimky.
Poznámka: Typ
decimalnení nutný k podpoře infinit nebo hodnot NaN, ale může to udělat; jeho rozsah může být menší než rozsahfloatadouble, ale není zaručeno, že. Udecimalreprezentací bez infinit nebo hodnot NaN a s rozsahem menším nežfloatje výsledek převodu nadecimalhodnotu nebofloatdoublenikdy nebude nekonečno nebo NaN. koncová poznámka
10.3.3 Explicitní výčtové převody
Explicitní převody výčtu jsou:
- Od
sbyte,byte,short,ushort, ,intuint,longulongcharfloatdoublenebodecimaldo jakékoli enum_type. - Z libovolné enum_type na , ,
sbytebyteshortushortintuintlong, ,ulong, , ,charnebo .floatdoubledecimal - Z libovolného enum_type do jakéhokoli jiného enum_type.
Explicitní převod výčtu mezi dvěma typy se zpracuje tak, že zachází se všemi zúčastněnými enum_type jako se základním typem tohoto enum_type a pak provede implicitní nebo explicitní číselný převod mezi výslednými typy.
Příklad: Při zadání enum_type
Es podkladovým typemintse převod zEnabytezpracuje jako explicitní číselný převod (§10.3.2) zintnabytea převod zbytenaEse zpracuje jako implicitní číselný převod (§10.2.3) zbytenaint. konec příkladu
10.3.4 Explicitní převody s možnou hodnotou null
Explicitní převody s možnou hodnotou null jsou převody s možnou hodnotou null (§10.6.1) odvozené z explicitních a implicitních předdefinovaných převodů.
10.3.5 Explicitní převody odkazů
Explicitní převody odkazů:
- Z objektu na jakýkoli jiný reference_type.
- Ze všech class_type
Sdo libovolného class_typeT, je poskytovánaSzákladní třídaT. - Z jakéhokoli , poskytnuté
Snení zapečetěno a poskytnuté není implementováno .T - Z jakéhokoli , poskytnuté
Snení zapečetěno ani poskytován implementuje .T - Z jakékoli interface_type
Sdo jakékoli interface_typeT, poskytnutéSnení odvozeno zT. -
s typem
SelementuSᵢs typemTelementu jsou splněny všechny následující podmínky:-
SaTliší se pouze v typu prvku. Jinými slovy,SaTmají stejný počet dimenzí. - Explicitní převod odkazu existuje z
SᵢdoTᵢ.
-
- Z
System.Arrayrozhraní, která implementuje, do libovolného array_type. - Z jednorozměrného array_type na , a jeho základní rozhraní za předpokladu, že existuje převod identity nebo explicitní odkaz převod z
S[]System.Collections.Generic.IList<T>.System.Collections.Generic.IReadOnlyList<T>ST - Z
System.Collections.Generic.IList<S>,System.Collections.Generic.IReadOnlyList<S>a jejich základní rozhraní na jednorozměrný typT[]pole , za předpokladu, že existuje převod identity nebo explicitní odkaz převod zSna T. - Z
System.Delegaterozhraní implementuje do libovolného delegate_type. - Z typu
Sodkazu na typ odkazuT, pokud má explicitní převod odkazu naStypT₀odkazu aT₀existuje převod identity zT₀naT. - Z referenčního typu
Sna rozhraní nebo typTdelegáta, pokud existuje explicitní převod odkazu zSrozhraní nebo typuT₀delegáta a buďT₀je variance-sklápěcí naTneboTje variance-sklápěcí naT₀§19.2.3.3. - Z
D<S₁...Sᵥ>místa, kdeD<T₁...Tᵥ>D<X₁...Xᵥ>je obecný typ delegáta,D<S₁...Sᵥ>není kompatibilní s nebo shodnýD<T₁...Tᵥ>s , a pro každý parametrXᵢtypu následujícíchDblokování:- Pokud
Xᵢje invariantní, pakSᵢje shodný sTᵢ. - Pokud
Xᵢje kovariantní, pak existuje převod identity, implicitní převod odkazu nebo explicitní převod odkazu zSᵢ.Tᵢ - Pokud
Xᵢje kontravariantní, pakSᵢjsouTᵢbuď identické, nebo oba odkazové typy.
- Pokud
- Explicitní převody zahrnující parametry typu, které jsou známé jako odkazové typy. Další podrobnosti o explicitních převodech zahrnujících parametry typu naleznete v § 10.3.8.
Explicitní převody odkazů jsou převody mezi reference_types, které vyžadují kontroly za běhu, aby se zajistilo, že jsou správné.
Aby byl převod explicitního odkazu úspěšný za běhu, musí být nullhodnota zdrojového operandu nebo typ objektu odkazovaného zdrojovým operandem typu, který lze převést na cílový typ implicitním převodem odkazu (§10.2.8). Pokud se explicitní převod odkazu nezdaří, System.InvalidCastException vyvolá se chyba.
Poznámka: Převody odkazů, implicitní nebo explicitní, nikdy nemění hodnotu samotného odkazu (§8.2.1), pouze jeho typ; ani nemění typ ani hodnotu odkazovaného objektu. koncová poznámka
10.3.6 Explicitní převody řazené kolekce členů
Explicitní převod existuje z výrazu E řazené kolekce členů na typ T řazené kolekce členů, pokud E má stejnýrit jako T a implicitní nebo explicitní převod existuje z každého prvku E do odpovídajícího typu elementu v T. Převod se provádí vytvořením instance odpovídajícího TSystem.ValueTuple<...> typu a inicializací každého z jeho polí v pořadí odleva doprava vyhodnocením odpovídajícího výrazu elementu Eřazené kolekce členů , převodem na odpovídající typ T prvku pomocí nalezen explicitního převodu a inicializací pole s výsledkem.
10.3.7 Konverze při rozbalení
Převod unboxing umožňuje explicitně převést reference_type na value_type. Existují následující převody pro rozbalení:
- Z typu
objectdo libovolného value_type. - Z typu
System.ValueTypedo libovolného value_type. - Z typu
System.Enumdo libovolného enum_type. - Z libovolného interface_type do libovolného non_nullable_value_type , který implementuje interface_type.
- Z libovolného interface_type do libovolného
Inon_nullable_value_type, kde existuje převod rozbalení zI₀a převod identity z doI. - Z jakéhokoli interface_type do libovolného
Inon_nullable_value_type, kde existuje převod rozbalení z interface_type na non_nullable_value_typeI₀a buďI₀je variance_convertible neboIIje variance-sklápěcí naI₀(§19.2.3.3). - Z libovolného reference_type do libovolného nullable_value_type, kde existuje převodod reference_type na podkladovou non_nullable_value_type nullable_value_type.
- Z parametru typu, o kterém není známo, že se jedná o typ hodnoty, aby převod byl povolen §10.3.8.
Operace rozbalení do non_nullable_value_type se skládá z první kontroly, že instance objektu je boxovaná hodnota daného non_nullable_value_type a poté zkopíruje hodnotu z instance.
Rozbalení na nullable_value_type vytvoří hodnotu null nullable_value_type pokud je zdrojový operand nebo zabalený výsledek rozbalení instance objektu na základní typ null jinak.
Poznámka: Odkaz na imaginární boxovací třídu popsanou v §10.2.9, rozbalení převodu pole objektu na value_type
Sse skládá z provádění výrazu((S_Boxing)box).value. Proto příkazyobject box = new S(); S s = (S)box;konceptuálně odpovídají
object box = new S_Boxing(new S()); S s = ((S_Boxing)box).value;koncová poznámka
Pro rozbalení převodu na danou non_nullable_value_type uspět za běhu musí být hodnota zdrojového operandu odkazem na boxovanou hodnotu tohoto non_nullable_value_type. Pokud je null zdrojový operand vyvolán System.NullReferenceException . Pokud je zdrojový operand odkazem na nekompatibilní objekt, System.InvalidCastException vyvolá se chyba.
Při rozbalení převodu na danou nullable_value_type , která bude úspěšná za běhu, musí být hodnota zdrojového operandu null nebo odkaz na boxovanou hodnotu podkladové non_nullable_value_typenullable_value_type. Pokud je zdrojový operand odkazem na nekompatibilní objekt, System.InvalidCastException vyvolá se chyba.
10.3.8 Explicitní převody zahrnující parametry typu
, o které je známo, že jde o referenční typ (T), existují následující explicitní převody (§10.3.5):
- Od efektivní základní třídy
CTdoTa z jakékoli základní třídyCdoT. - Z libovolného interface_type do
T. - Od
Tjakékoli interface_typeIza předpokladu, že neexistuje implicitní převod odkazu zTnaI. -
Od type_parameter
UpoTposkytnutí, kteráTzávisí naU(§15.2.5).Poznámka: Vzhledem k tomu
T, že je známo, že se jedná o typ odkazu, v rámci oboruT, bude typ běhu vždy odkazový typ, i kdyžUnení známo, že se jedná o typ odkazu v době kompilace. koncová poznámka
, o němž neníTjde o odkazový typ (§15.2.5), jsou při kompilaci považovány za převodyT). Pokud je to typ hodnoty za běhu T , provede se převod jako unboxing conversion. Pokud se jedná o typ odkazu, provede se převod za běhu T jako explicitní převod odkazu nebo převod identity.
- Od efektivní základní třídy
CTdoTa z jakékoli základní třídyCdoT.Poznámka: C bude jedním z typů
System.Object,System.ValueTypeneboSystem.Enum(jinakTby bylo známo, že se jednat o odkazový typ). koncová poznámka - Z libovolného interface_type do
T.
, o kterých neníTjde o odkazový typ (§15.2.5), existují následující explicitní převody:
- Od
Tjakékoli interface_typeIza předpokladu, že již není implicitní převod zTnaI. Tento převod se skládá z implicitního převodu boxingu (§10.2.9) odTobjectnásledného explicitního převodu naobjectI. Pokud je to typ hodnoty za běhuT, provede se převod jako převod boxingu následovaný explicitním převodem odkazu. Pokud jde o typ odkazu,Tprovede se převod za běhu jako explicitní převod odkazu. - Od parametru
Utypu, kterýTTzávisí naU(§15.2.5). Je-liTto typ hodnoty aUjedná se o referenční typ, provede se převod jako převod rozbalení. Pokud jsou obaTtypyUhodnot za běhu, pakTaUjsou nutně stejného typu a neprovádí se žádný převod. V době běhu je-liTtyp odkazu, pakUje nutně také referenčním typem a převod se provede jako explicitní převod odkazu nebo převod identity.
Ve všech případech pravidla zajišťují, aby byl převod proveden jako převod bez složky, pokud a pouze v případě, že převod je za běhu převodu z referenčního typu na typ hodnoty.
Výše uvedená pravidla neumožňují přímý explicitní převod z parametru nekontrénovaného typu na typ bez rozhraní, což může být překvapivý. Důvodem tohoto pravidla je zabránit nejasnostem a vyčistit sémantiku těchto převodů.
Příklad: Zvažte následující deklaraci:
class X<T> { public static long F(T t) { return (long)t; // Error } }Pokud přímý explicitní převod
tnalongbyl povolen, jeden by mohl snadno očekávat, žeX<int>.F(7)by se vrátil7L. To by však nebylo, protože standardní číselné převody jsou považovány pouze tehdy, když jsou typy známé jako číselné v době vazby. Aby bylo možné sémantiku smazat, musí být místo toho napsán výše uvedený příklad:class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }Tento kód se nyní zkompiluje, ale při provádění
X<int>.F(7)by pak vyvolal výjimku za běhu, protože poleintnelze převést přímo nalong.konec příkladu
10.3.9 Explicitní převody definované uživatelem
Explicitní převod definovaný uživatelem se skládá z volitelného standardního explicitního převodu, po kterém následuje spuštění uživatelem definovaného implicitního nebo explicitního převodního operátoru následovaného dalším volitelným standardním explicitním převodem. Přesná pravidla pro vyhodnocení explicitních převodů definovaných uživatelem jsou popsána v §10.5.5.
10.4 Standardní převody
10.4.1 Obecné
Standardní převody jsou ty předdefinované převody, ke kterým může dojít jako součást převodu definovaného uživatelem.
10.4.2 Standardní implicitní převody
Následující implicitní převody jsou klasifikovány jako standardní implicitní převody:
- Převody identit (§10.2.2)
- Implicitní číselné převody (§10.2.3)
- Implicitní převody s možnou hodnotou null (§10.2.6)
- Převody literálů null (§10.2.7)
- Implicitní převody odkazů (§10.2.8)
- Převody krabic (§10.2.9)
- Implicitní převody konstantních výrazů (§10.2.11)
- Implicitní převody zahrnující parametry typu (§10.2.12)
Standardní implicitní převody výslovně vylučují implicitní převody definované uživatelem.
10.4.3 Standardní explicitní převody
Standardní explicitní převody jsou všechny standardní implicitní převody plus podmnožina explicitních převodů, pro které existuje opačný standardní implicitní převod.
Poznámka: Jinými slovy, pokud standardní implicitní převod existuje z typu
Ana typB, pak standardní explicitní převod existuje z typu na typABa z typuBna typA. koncová poznámka
10.5 Převody definované uživatelem
10.5.1 Obecné
Jazyk C# umožňuje rozšíření předem definovaných implicitních a explicitních převodů pomocí uživatelsky definovaných převodů. Uživatelem definované převody se zavádějí deklarací operátorů převodu (§15.10.4) ve třídách a typech struktur.
10.5.2 Povolené uživatelem definované převody
Jazyk C# umožňuje deklarovat pouze určité uživatelem definované převody. Konkrétně není možné předefinovat již existující implicitní nebo explicitní převod.
Pro daný typ zdroje a cílový typ ST, pokud S nebo T jsou typy hodnot null, let S₀ a T₀ odkazovat na jejich základní typy, jinak S₀ a T₀ jsou rovny S a T v uvedeném pořadí. Třída nebo struktura je povolena deklarovat převod ze zdrojového typu na cílový typ ST pouze v případě, že jsou splněny všechny následující podmínky:
-
S₀aT₀jsou různé typy. - Buď
S₀nebo je třída neboT₀typ struktury, ve které se provádí deklarace operátoru. - Ani
S₀interface_typeT₀. - S výjimkou uživatelem definovaných převodů neexistuje převod z
SdoTnebo zTdoS.
Omezení, která se vztahují na uživatelem definované převody, jsou uvedena v §15.10.4.
10.5.3 Vyhodnocení uživatelsky definovaných převodů
Převod definovaný uživatelem převede zdrojový výraz, který může mít typ zdroje, na jiný typ, který se nazývá cílový typ. Vyhodnocení uživatelem definovaných konverzních center při hledání nejvýraznějšího uživatelem definovaného operátoru převodu pro zdrojový výraz a cílový typ. Toto určení je rozděleno do několika kroků:
- Nalezení sady tříd a struktur, ze kterých se budou považovat uživatelem definované operátory převodu. Tato sada se skládá ze zdrojového typu a jeho základních tříd, pokud existuje zdrojový typ spolu s cílovým typem a jeho základními třídami. Pro tento účel se předpokládá, že pouze třídy a struktury mohou deklarovat uživatelem definované operátory a že typy bez tříd nemají žádné základní třídy. Pokud je zdrojový nebo cílový typ typu nullable-value-type, použije se místo toho jejich základní typ.
- Z této sady typů určíte, které operátory převodu definované uživatelem a které se používají. Aby byl operátor převodu použitelný, je možné provést standardní převod (§10.4) ze zdrojového výrazu na typ operandu operátora a musí být možné provést standardní převod z typu výsledku operátoru na cílový typ.
- Ze sady použitelných uživatelsky definovaných operátorů určuje, který operátor je jednoznačně nejvýraznější. Obecně platí, že nejvýraznější operátor je operátor, jehož typ operandu je "nejblíže" ke zdrojovému výrazu a jehož typ výsledku je "nejblíže" cílovému typu. Uživatelem definované operátory převodu se preferují před operátory přepočítání metodou lifted. Přesná pravidla pro vytvoření nejpřesnějšího uživatelem definovaného operátoru převodu jsou definována v následujících dílčích návazcích.
Jakmile identifikujete nejvýraznějšího uživatelem definovaného operátoru převodu, skutečné spuštění uživatelem definovaného převodu zahrnuje až tři kroky:
- Nejprve v případě potřeby provedete standardní převod ze zdrojového výrazu na typ operandu definovaného uživatelem nebo zvedaným operátorem převodu.
- Dále vyvolání uživatelem definovaného nebo zvednutého operátoru převodu k provedení převodu.
- V případě potřeby proveďte standardní převod z typu výsledku uživatelem definovaného operátoru převodu na cílový typ.
Vyhodnocení uživatelem definovaného převodu nikdy nezahrnuje více než jeden uživatelem definovaný nebo lifted převodní operátor. Jinými slovy, převod z typu S na typ T nikdy nespustí uživatelsky definovaný převod z S do X a pak spustí uživatelsky definovaný převod z X do T.
- Přesné definice vyhodnocení implicitních nebo explicitních převodů definovaných uživatelem jsou uvedeny v následujících dílčích počtech. Definice používají následující termíny:
- Pokud existuje standardní implicitní převod (§ 10.4.2) z typu
Ana typBa jestližeAaniBnejsou interface_type, pak se říká, žeAje zahrnutBaBse říká, že zahrnujeA. - Pokud standardní implicitní převod (§10.4.2) existuje z výrazu
Ena typB, a pokudBani typE(pokud ho má), interface_types, pakEje zahrnujeBaBje uvedeno, zahrnujeE. - Nejobsahující typ v sadě typů je jeden typ, který zahrnuje všechny ostatní typy v sadě. Pokud žádný typ nezahrne všechny ostatní typy, sada neobsahuje nejobsahující typ. Intuitivnějším způsobem je nejobsáhlejší typ "největší" v sadě – typ, na který lze implicitně převést každý z ostatních typů.
- Nejobsáhodnější typ v sadě typů je jeden typ, který je zahrnut všemi ostatními typy v sadě. Pokud žádný jeden typ nezahrne všechny ostatní typy, sada neobsahuje nejobsáženější typ. Intuitivnějším způsobem je nejobsáhlejší typ "nejmenší" v sadě – jeden typ, který lze implicitně převést na každý z ostatních typů.
10.5.4 Uživatelem definované implicitní převody
Implicitní převod z výrazu E na typ T definovaný uživatelem se zpracuje následujícím způsobem:
Určete typy
SS₀aT₀.- Pokud
Etyp obsahuje, nechteStento typ. - Pokud
SneboTjsou typy hodnot s možnou hodnotou null, letSᵢaTᵢbýt jejich podkladové typy, jinak letSᵢa beTᵢaST, v uvedeném pořadí. - Pokud
SᵢneboTᵢjsou parametry typu, letS₀aT₀být jejich efektivní základní třídy, jinak letS₀a býtT₀aSᵢTᵢ, v uvedeném pořadí.
- Pokud
Najděte sadu typů,
Dze kterých se budou považovat uživatelem definované operátory převodu. Tato sada se skládá zS₀(pokudS₀existuje a je třída nebo struktura), základní třídyS₀(pokudS₀existuje a je třída) aT₀(pokudT₀je třída nebo struktura). Typ se přidá do sadyDpouze v případě, že převod identity na jiný typ, který už je součástí sady, neexistuje.Vyhledejte sadu použitelných uživatelsky definovaných a zvednutých operátorů převodu.
UTato sada se skládá z uživatelem definovaných a zvednutí implicitních konverzních operátorů deklarovaných třídami nebo strukturami,Dkteré převádějí z typu zahrnujícíhoEtyp, kterýTzahrnuje . PokudUje prázdný, převod není definován a dojde k chybě v době kompilace.Vyhledejte nejvýraznější typ zdroje ,
Sₓoperátory vU:- Pokud
Sexistuje a některý z operátorů vUpřevodu zS, pakSₓjeS. -
SₓV opačném případě je nejvíce zahrnutý typ v kombinované množině zdrojových typů operátorů vU. Pokud nelze najít přesně jeden nejobsáhodnější typ, převod je nejednoznačný a dojde k chybě v době kompilace.
- Pokud
Vyhledejte nejvýraznější cílový typ ,
Tₓoperátory vU:- Pokud některý z operátorů v
Upřevodu naT, pakTₓjeT. -
TₓV opačném případě je nejvíce zahrnující typ v kombinované množině cílových typů operátorů vU. Pokud nelze najít přesně jeden typ zahrnující nejvíce, převod je nejednoznačný a dojde k chybě v době kompilace.
- Pokud některý z operátorů v
Vyhledejte nejvýraznější operátor převodu:
- Pokud
Uobsahuje přesně jeden uživatelem definovaný operátor převodu, který se převede zSₓnaTₓ, pak je to nejvýraznější operátor převodu. - V opačném případě, pokud
Uobsahuje přesně jeden zdvižený převodní operátor, který převádí zSₓnaTₓ, pak je to nejvýraznější převodní operátor. - V opačném případě je převod nejednoznačný a dojde k chybě v době kompilace.
- Pokud
Nakonec použijte převod:
- Pokud E typ ještě nemá
Sₓ, provede se standardní implicitní převod zEnaSₓ. - Nejvýraznější operátor převodu je vyvolán pro převod z
SₓnaTₓ. - Pokud
Tₓtomu tak neníT, provede se standardní implicitní převod zTₓnaT.
- Pokud E typ ještě nemá
Uživatelem definovaný implicitní převod z typu S na typ T existuje, pokud uživatelem definovaný implicitní převod existuje z proměnné typu S do T.
Explicitní převody definované uživatelem 10.5.5
Explicitní převod z výrazu E na typ T definovaný uživatelem se zpracuje takto:
- Určete typy
SS₀aT₀.- Pokud
Etyp obsahuje, nechteStento typ. - Pokud
SneboTjsou typy hodnot s možnou hodnotou null, letSᵢaTᵢbýt jejich podkladové typy, jinak letSᵢa beTᵢaST, v uvedeném pořadí. - Pokud
SᵢneboTᵢjsou parametry typu, letS₀aT₀být jejich efektivní základní třídy, jinak letS₀a býtT₀aSᵢTᵢ, v uvedeném pořadí.
- Pokud
- Najděte sadu typů,
Dze kterých se budou považovat uživatelem definované operátory převodu. Tato sada se skládá zS₀(pokudS₀existuje a je třída nebo struktura), základní třídyS₀(pokudS₀existuje a je třída),T₀(pokudT₀je třída nebo struktura) a základní třídyT₀(pokudT₀je třída). Typ se přidá do sadyDpouze v případě, že převod identity na jiný typ, který už je součástí sady, neexistuje. - Vyhledejte sadu použitelných uživatelsky definovaných a zvednutých operátorů převodu.
UTato sada se skládá z uživatelem definovaných a zvednutí implicitních nebo explicitních konverzních operátorů deklarovaných třídami nebo strukturami,Dkteré převádějí z typu zahrnujícíhoEnebo zahrnutéhoS(pokud existuje) na typ zahrnující nebo zahrnujícíT. PokudUje prázdný, převod není definován a dojde k chybě v době kompilace. - Vyhledejte nejvýraznější typ zdroje ,
Sₓoperátory vU:- Pokud S existuje a některý z operátorů v
Upřevodu zS, pakSₓjeS. - Jinak platí, že pokud některý z operátorů
U, které převedou na typy, které zahrnujíE, je nejzahrnulejšímSₓtypem v kombinované sadě zdrojových typů těchto operátorů. Pokud nelze najít nejobsáhodnější typ, převod je nejednoznačný a dojde k chybě v době kompilace. -
SₓV opačném případě je nejvíce zahrnující typ v kombinované množině zdrojových typů operátorů vU. Pokud nelze najít přesně jeden typ zahrnující nejvíce, převod je nejednoznačný a dojde k chybě v době kompilace.
- Pokud S existuje a některý z operátorů v
- Vyhledejte nejvýraznější cílový typ ,
Tₓoperátory vU:- Pokud některý z operátorů v
Upřevodu naT, pakTₓjeT. - V opačném případě platí, že pokud některý z operátorů převedou
Una typy, které jsou zahrnutyT, pakTₓje nejvíce zahrnující typ v kombinované množině cílových typů těchto operátorů. Pokud nelze najít přesně jeden typ zahrnující nejvíce, převod je nejednoznačný a dojde k chybě v době kompilace. -
TₓV opačném případě je nejobsáhodnější typ v kombinované množině cílových typů operátorů vU. Pokud nelze najít nejobsáhodnější typ, převod je nejednoznačný a dojde k chybě v době kompilace.
- Pokud některý z operátorů v
- Vyhledejte nejvýraznější operátor převodu:
- Pokud U obsahuje přesně jeden uživatelem definovaný operátor převodu, který se převede z
SₓnaTₓ, pak je to nejvýraznější operátor převodu. - V opačném případě, pokud
Uobsahuje přesně jeden zdvižený převodní operátor, který převádí zSₓnaTₓ, pak je to nejvýraznější převodní operátor. - V opačném případě je převod nejednoznačný a dojde k chybě v době kompilace.
- Pokud U obsahuje přesně jeden uživatelem definovaný operátor převodu, který se převede z
- Nakonec použijte převod:
- Pokud
Etyp ještě nemáSₓ, provede se standardní explicitní převod z E naSₓ. - Nejvýraznější uživatelem definovaný operátor převodu je vyvolán pro převod z
SₓnaTₓ. - Pokud
Tₓtomu tak neníT, provede se standardní explicitní převod zTₓnaT.
- Pokud
Uživatelem definovaný explicitní převod z typu S na typ T existuje, pokud uživatelem definovaný explicitní převod existuje z proměnné typu S na T.
10.6 Převody zahrnující typy s možnou hodnotou null
10.6.1 Převody s možnou hodnotou Null
Převod s možnou hodnotou null umožňuje předdefinovaný převod, který funguje s typem hodnoty, který není nullable, lze použít také s tvarem s možnou hodnotou null daného typu. Pro každý z předdefinovaných implicitních nebo explicitních převodů, které převedou typ hodnoty bez S hodnoty null na typ T hodnoty, který není nullable (§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 a §10.3.3), existují následující převody s možnou hodnotou null:
- Implicitní nebo explicitní převod z
S?T? - Implicitní nebo explicitní převod z
ST? - Explicitní převod z
S?naT.
Převod s možnou hodnotou null je sám klasifikován jako implicitní nebo explicitní převod.
Některé převody s možnou hodnotou null jsou klasifikovány jako standardní převody a mohou nastat jako součást uživatelem definovaného převodu. Konkrétně všechny implicitní převody s možnou hodnotou null jsou klasifikovány jako standardní implicitní převody (§10.4.2) a tyto explicitní převody s možnou hodnotou null, které splňují požadavky §10.4.3 , jsou klasifikovány jako standardní explicitní převody.
Vyhodnocení převodu s možnou hodnotou null na základě podkladového převodu z S výnosu T následujícím způsobem:
- Pokud je převod s možnou hodnotou null:
S?T?- Pokud je zdrojová hodnota null (
HasValuevlastnost jefalse), výsledek je null hodnota typuT?. - V opačném případě se převod vyhodnotí jako rozbalení z
S?doS, následované podkladovým převodem zSnaT, následované zabalením zTdoT?.
- Pokud je zdrojová hodnota null (
- Pokud je převod s možnou hodnotou null od
SdoT?, převod se vyhodnotí jako podkladový převod zSnaTnásledný obtékání zTdoT?. - Pokud je převod s možnou hodnotou null od
S?doT, převod se vyhodnotí jako přepsání zS?naSnásledný podkladový převod zSdoT.
10.6.2 Zvedané převody
Vzhledem k tomu, že uživatelem definovaný převodní operátor, který převádí z nenulovatelného typu S hodnoty na nenulový typ Thodnoty , existuje operátor převést z S? na T?. Tento operátor zrušeného převodu provede rozbalení z S? na S základě uživatelem definovaného převodu na ST zalamování z T do T?, s výjimkou toho, že hodnota S? null se převede přímo na hodnotu null s T?hodnotou null . Operátor lifted conversion má stejnou implicitní nebo explicitní klasifikaci jako základní uživatelem definovaný operátor převodu.
10.7 Převody anonymních funkcí
10.7.1 Obecné
Anonymous_method_expression nebo lambda_expression je klasifikován jako anonymní funkce (§12.21). Výraz nemá typ, ale lze jej implicitně převést na kompatibilní typ delegáta. Některé výrazy lambda mohou být také implicitně převedeny na kompatibilní typ stromu výrazu.
Anonymní funkce F je konkrétně kompatibilní s zadaným typem D delegáta:
- Pokud
Fobsahuje anonymous_function_signature, pakDaFmít stejný počet parametrů. - Pokud
Fneobsahuje anonymous_function_signature,Dmůže mít nula nebo více parametrů libovolného typu, pokud žádný parametrDnení výstupním parametrem. - Pokud
Fmá explicitně zadaný seznam parametrů, každý parametr máDstejné modifikátory jako odpovídající parametr aFmezi odpovídajícím parametrem vFsouboru existuje převod identity. - Pokud
Fobsahuje implicitně zadaný seznam parametrů,Dnemá žádné odkazy ani výstupní parametry. - Pokud je tělo
Fvýraz a buďDmá návratový typ void neboFje asynchronní aDmá«TaskType»návratový typ (§15.14.1), pak když je každému parametruFudělen typ odpovídajícího parametru vD, je těloFplatný výraz (w.r.t §12), který by byl povolen jako statement_expression (§13.7). - Pokud je tělo
Fbloku a má návratový typDje asynchronní a má návratovýFtyp , pak když je každému parametruDzadán typ odpovídajícího parametru v«TaskType», je textFplatného bloku (w.r.tD), ve kterém žádnýFpříkaz neurčuje výraz. - Pokud je tělo
Fvýrazem a buďFnení asynchronní aDmá ne-voidnávratový typT, neboFje asynchronní aDmá«TaskType»<T>návratový typ (§15.14.1), pak když je každému parametruFudělen typ odpovídajícího parametru vD, je tělo platnýmFvýrazem (v rámci §12), který je implicitně převeditelný naT. - Pokud je tělo
Fbloku a buďFje nesynchronní aDmá nesynchronní návratový typT, je asynchronní aFmáDnávratový typ, pak když je každému parametru udělen typ odpovídajícího parametru«TaskType»<T>vF, je text platnéhoDbloku příkazu (w.r.tF) s nedostupným koncovým bodem, ve kterém každý návratový příkaz určuje výraz, který je implicitně převést na .
Příklad: Následující příklady ilustrují tato pravidla:
delegate void D(int x); D d1 = delegate { }; // Ok D d2 = delegate() { }; // Error, signature mismatch D d3 = delegate(long x) { }; // Error, signature mismatch D d4 = delegate(int x) { }; // Ok D d5 = delegate(int x) { return; }; // Ok D d6 = delegate(int x) { return x; }; // Error, return type mismatch delegate void E(out int x); E e1 = delegate { }; // Error, E has an output parameter E e2 = delegate(out int x) { x = 1; }; // Ok E e3 = delegate(ref int x) { x = 1; }; // Error, signature mismatch delegate int P(params int[] a); P p1 = delegate { }; // Error, end of block reachable P p2 = delegate { return; }; // Error, return type mismatch P p3 = delegate { return 1; }; // Ok P p4 = delegate { return "Hello"; }; // Error, return type mismatch P p5 = delegate(int[] a) // Ok { return a[0]; }; P p6 = delegate(params int[] a) // Error, params modifier { return a[0]; }; P p7 = delegate(int[] a) // Error, return type mismatch { if (a.Length > 0) return a[0]; return "Hello"; }; delegate object Q(params int[] a); Q q1 = delegate(int[] a) // Ok { if (a.Length > 0) return a[0]; return "Hello"; };konec příkladu
Příklad: Následující příklady používají obecný typ
Func<A,R>delegáta, který představuje funkci, která přebírá argument typuAa vrací hodnotu typuR:delegate R Func<A,R>(A arg);V zadáních
Func<int,int> f1 = x => x + 1; // Ok Func<int,double> f2 = x => x + 1; // Ok Func<double,int> f3 = x => x + 1; // Error Func<int, Task<int>> f4 = async x => x + 1; // Okparametr a návratové typy každé anonymní funkce jsou určeny z typu proměnné, ke které je anonymní funkce přiřazena.
První přiřazení úspěšně převede anonymní funkci na typ
Func<int,int>delegáta, protože pokudxje daný typint,x + 1je platný výraz, který je implicitně převoditelný na typint.Podobně druhé přiřazení úspěšně převede anonymní funkci na typ delegáta Func<int, double> , protože výsledek
x + 1(typuint) je implicitně převoditelný na typdouble.Třetí přiřazení je však chyba v době kompilace, protože pokud
xje daný typdouble, výsledekx + 1(typudouble) není implicitně konvertibilní na typint.Čtvrté přiřazení úspěšně převede anonymní asynchronní funkci na typ
Func<int, Task<int>>delegáta, protože výsledekx + 1(typuint) je implicitně převoditelný na efektivní návratový typintasynchronní lambda, který má návratový typTask<int>.konec příkladu
Výraz F lambda je kompatibilní se stromovým typem Expression<D> výrazu, pokud F je kompatibilní s typem Ddelegáta . To neplatí pro anonymní metody, pouze výrazy lambda.
Anonymní funkce můžou ovlivnit rozlišení přetížení a účastnit se odvozování typu. Další podrobnosti naleznete v §12.6 .
10.7.2 Vyhodnocení převodů anonymních funkcí na typy delegátů
Převod anonymní funkce na typ delegáta vytvoří instanci delegáta, která odkazuje na anonymní funkci a (pravděpodobně prázdnou) sadu zachycených vnějších proměnných, které jsou aktivní v době vyhodnocení. Při vyvolání delegáta se spustí tělo anonymní funkce. Kód v těle se spustí pomocí sady zachycených vnějších proměnných odkazovaných delegátem. Delegate_creation_expression (§12.8.17.5) lze použít jako alternativní syntaxi pro převod anonymní metody na typ delegáta.
Seznam vyvolání delegáta vytvořeného z anonymní funkce obsahuje jednu položku. Přesný cílový objekt a cílová metoda delegáta nejsou zadány. Konkrétně není určeno, zda cílový objekt delegáta je null, this hodnota ohraničujícího členu funkce nebo nějaký jiný objekt.
Převody sémanticky identických anonymních funkcí se stejnou (případně prázdnou) sadou zachycených instancí vnějších proměnných na stejné typy delegátů jsou povoleny (ale nevyžadují) k vrácení stejné instance delegáta. Termín sémanticky identický se zde používá k tomu, že provádění anonymních funkcí ve všech případech způsobí stejné účinky vzhledem ke stejným argumentům. Toto pravidlo povoluje optimalizaci kódu, například následující.
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a, Function f)
{
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++)
{
result[i] = f(a[i]);
}
return result;
}
static void F(double[] a, double[] b)
{
a = Apply(a, (double x) => Math.Sin(x));
b = Apply(b, (double y) => Math.Sin(y));
...
}
}
Vzhledem k tomu, že dva delegáti anonymní funkce mají stejnou (prázdnou) sadu zachycených vnějších proměnných a vzhledem k tomu, že anonymní funkce jsou sémanticky identické, je povoleno, aby delegáti odkazovali na stejnou cílovou metodu. Kompilátoru je skutečně povoleno vrátit stejnou instanci delegáta z obou výrazů anonymní funkce.
10.7.3 Vyhodnocení převodů výrazů lambda na typy stromu výrazů
Převod výrazu lambda na typ stromu výrazu vytvoří strom výrazu (§8.6). Přesněji řečeno, vyhodnocení převodu výrazu lambda vytváří objektovou strukturu, která představuje strukturu samotného výrazu lambda.
Ne každý výraz lambda lze převést na typy stromu výrazů. Převod na kompatibilní typ delegáta vždy existuje, ale může selhat v době kompilace z důvodů definovaných implementací.
Poznámka: Mezi běžné důvody, proč se výraz lambda nepodaří převést na typ stromu výrazů, patří:
- Má blokové tělo.
asyncMá modifikátor.- Obsahuje operátor přiřazení.
- Obsahuje výstupní nebo referenční parametr.
- Obsahuje dynamicky vázané výrazy.
koncová poznámka
10.8 Převody skupin metod
Implicitní převod existuje ze skupiny metod (§12.2) na kompatibilní typ delegáta (§21.4). Je-li D typ delegáta a E je výraz klasifikovaný jako skupina metod, je kompatibilní D s E tím, zda a pouze pokud E obsahuje alespoň jednu metodu, která je použitelná v normální podobě (§12.6.4.2) k libovolnému seznamu argumentů (§12.6.2) s typy a modifikátory odpovídajícími typům parametrů a modifikátorům D, jak je popsáno v následujících bodech.
Použití převodu ze skupiny E metod na typ D delegáta v době kompilace je popsáno v následujícím příkladu.
- Jedna metoda
Mje vybrána odpovídající vyvolání metody (§12.8.10.2) formulářeE(A)s následujícími úpravami:- Seznam
Aargumentů je seznam výrazů, každý klasifikovaný jako proměnná a s typem a modifikátorem (in,outneboref) odpovídajícího parametru v parameter_list –Ds výjimkou parametrů typudynamic, kde odpovídající výraz má typobjectmístodynamic. - Považované metody jsou pouze metody použitelné v jejich normální podobě a nevylučují žádné volitelné parametry (§12.6.4.2). Kandidátské metody jsou tedy ignorovány, pokud jsou použitelné pouze v rozšířené podobě, nebo pokud jeden nebo více jejich volitelných parametrů nemá odpovídající parametr v
D.
- Seznam
- Převod je považován za existenci, pokud algoritmus §12.8.10.2 vytváří jedinou nejlepší metodu
M, která je kompatibilní (§21.4) sD. - Pokud je vybraná metoda
Minstance metoda, výraz instance přidruženýEk určuje cílový objekt delegáta. - Pokud je vybraná metoda rozšiřující metodou
M, která je označena pomocí přístupu člena ve výrazu instance, tento výraz instance určuje cílový objekt delegáta. - Výsledkem převodu je hodnota typu
D, konkrétně delegát, který odkazuje na vybranou metodu a cílový objekt.
Příklad: Následující příklad ukazuje převody skupin metod:
delegate string D1(object o); delegate object D2(string s); delegate object D3(); delegate string D4(object o, params object[] a); delegate string D5(int i); class Test { static string F(object o) {...} static void G() { D1 d1 = F; // Ok D2 d2 = F; // Ok D3 d3 = F; // Error – not applicable D4 d4 = F; // Error – not applicable in normal form D5 d5 = F; // Error – applicable but not compatible } }Přiřazení, které
d1implicitně převede skupinuFmetod na hodnotu typuD1.Přiřazení, které
d2ukazuje, jak je možné vytvořit delegáta na metodu, která má méně odvozené (kontravariantní) typy parametrů a více odvozenější (kovariantní) návratový typ.Přiřazení, které
d3ukazuje, jak neexistuje žádný převod, pokud metoda není použitelná.Přiřazení, které ukazuje
d4, jak musí být metoda použitelná v normální podobě.Přiřazení, které
d5ukazuje, jak se parametry a návratové typy delegáta a metody mohou lišit pouze pro odkazové typy.konec příkladu
Stejně jako u všech ostatních implicitních a explicitních převodů lze operátor přetypování použít k explicitnímu provedení konkrétního převodu.
Příklad: Příklad
object obj = new EventHandler(myDialog.OkClick);místo toho by bylo možné napsat
object obj = (EventHandler)myDialog.OkClick;konec příkladu
Převod skupiny metod může odkazovat na obecnou metodu, a to buď explicitním zadáním argumentů typu v rámci E, nebo prostřednictvím odvození typu (§12.6.3). Pokud se použije odvození typu, typy parametrů delegáta se použijí jako typy argumentů v procesu odvozování. Návratový typ delegáta se nepoužívá k odvozování. Zda jsou zadány nebo odvozeny argumenty typu, jsou součástí procesu převodu skupiny metod; jedná se o argumenty typu použité k vyvolání cílové metody při vyvolání výsledného delegáta.
Příklad:
delegate int D(string s, int i); delegate int E(); class X { public static T F<T>(string s, T t) {...} public static T G<T>() {...} static void Main() { D d1 = F<int>; // Ok, type argument given explicitly D d2 = F; // Ok, int inferred as type argument E e1 = G<int>; // Ok, type argument given explicitly E e2 = G; // Error, cannot infer from return type } }konec příkladu
Skupiny metod mohou ovlivnit rozlišení přetížení a účastnit se odvozování typů. Další podrobnosti naleznete v §12.6 .
Vyhodnocení běhu převodu skupiny metod probíhá takto:
- Pokud je metoda vybraná při kompilaci metodou instance nebo je to rozšiřující metoda, ke které se přistupuje jako metoda instance, je cílový objekt delegáta určen z výrazu instance přidruženého k
E:- Výraz instance se vyhodnotí. Pokud toto vyhodnocení způsobí výjimku, neprojdou žádné další kroky.
- Pokud je výraz instance reference_type, hodnota vypočítaná výrazem instance se stane cílovým objektem. Pokud je vybraná metoda instance a cílový objekt je
null,System.NullReferenceExceptionje vyvolán a nejsou provedeny žádné další kroky. - Pokud je výraz instance value_type, provede se operace boxingu (§10.2.9) pro převod hodnoty na objekt a tento objekt se stane cílovým objektem.
- Jinak je vybraná metoda součástí volání statické metody a cílový objekt delegáta je
null. - Instance delegáta typu
Ddelegáta je získána s odkazem na metodu určenou v době kompilace a odkaz na cílový objekt vypočítaný výše, jak je znázorněno níže:- Převod je povolen (ale není vyžadován) k použití existující instance delegáta, která již tyto odkazy obsahuje.
- Pokud existující instance nebyla znovu použita, vytvoří se nový (§21.5). Pokud není k dispozici dostatek paměti pro přidělení nové instance,
System.OutOfMemoryExceptionvyvolá se vyvolá. V opačném případě se instance inicializuje s danými odkazy.
ECMA C# draft specification