Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
10.1 Ogólne
Konwersja powoduje przekonwertowanie wyrażenia na określony typ lub traktowanie go jako określonego typu. W poprzednim przypadku konwersja może obejmować zmianę reprezentacji. Konwersje mogą być niejawne lub jawne, a to określa, czy jest wymagane jawne rzutowanie.
Przykład: na przykład konwersja typu na typ
intlongjest niejawna, więc wyrażenia typuintmogą być niejawnie traktowane jako typlong. Odwrotna konwersja, od typu do typulongint, jest jawna i dlatego wymagane jest jawne rzutowanie.int a = 123; long b = a; // implicit conversion from int to long int c = (int) b; // explicit conversion from long to intprzykład końcowy
Niektóre konwersje są definiowane przez język. Programy mogą również definiować własne konwersje (§10.5).
Niektóre konwersje w języku są definiowane z wyrażeń na typy, a inne od typów do typów. Konwersja typu ma zastosowanie do wszystkich wyrażeń, które mają ten typ.
Przykład:
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;przykład końcowy
10.2 Niejawne konwersje
10.2.1 Ogólne
Następujące konwersje są klasyfikowane jako niejawne konwersje:
- Konwersje tożsamości (§10.2.2)
- Niejawne konwersje liczbowe (§10.2.3)
- Niejawne konwersje wyliczenia (§10.2.4)
- Niejawne konwersje ciągów interpolowanych (§10.2.5)
- Niejawne konwersje odwołań (§10.2.8)
- Konwersje boksu (§10.2.9)
- Niejawne konwersje dynamiczne (§10.2.10)
- Niejawne konwersje parametrów typu (§10.2.12)
- Niejawne konwersje wyrażeń stałych (§10.2.11)
- Konwersje niejawne zdefiniowane przez użytkownika (w tym zniesione) (§10.2.14)
- Konwersje funkcji anonimowych (§10.2.15)
- Konwersje grup metod (§10.2.15)
- Konwersje literału null (§10.2.7)
- Niejawne konwersje dopuszczane do wartości null (§10.2.6)
- Niejawne konwersje krotki (§10.2.13)
- Domyślne konwersje literału (§10.2.16)
- Niejawne konwersje rzutów (§10.2.17)
Konwersje niejawne mogą wystąpić w różnych sytuacjach, w tym wywołania składowych funkcji (§12.6.6), wyrażenia rzutowania (§12.9.8) i przypisania (§12.23).
Wstępnie zdefiniowane konwersje niejawne zawsze kończą się powodzeniem i nigdy nie powodują zgłaszania wyjątków.
Uwaga: Prawidłowo zaprojektowane niejawne konwersje zdefiniowane przez użytkownika powinny również wykazywać te cechy. notatka końcowa
Do celów konwersji typy object i dynamic są tożsamościami konwertowane (§10.2.2).
Jednak konwersje dynamiczne (§10.2.10) mają zastosowanie tylko do wyrażeń typu dynamic (§8.2.4).
10.2.2 Konwersja tożsamości
Konwersja tożsamości jest konwertowana z dowolnego typu na ten sam typ lub typ, który jest odpowiednikiem w czasie wykonywania. Jedną z przyczyn, dla których ta konwersja istnieje, jest taka, że typ T lub wyrażenie typu T można powiedzieć, że jest konwertowany na T siebie. Istnieją następujące konwersje tożsamości:
- Między
TiTdla dowolnego typuT. - Między
TiT?dla dowolnego typuTodwołania . - Między
objectidynamic. - Między wszystkimi typami krotki o tej samej arity i odpowiadającym im typem skonstruowanym
ValueTuple<...>, gdy istnieje konwersja tożsamości między każdą parą odpowiednich typów elementów. - Między typami utworzonymi z tego samego typu ogólnego, w którym istnieje konwersja tożsamości między każdym odpowiadającym argumentem typu.
Przykład: Poniżej przedstawiono cyklisywny charakter trzeciej reguły:
(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 krotki
t1it2t3wszystkie mają dwa elementy: pointstringnim element . Typy elementów krotki mogą się składać z krotki, tak jak wt4elementach ,t5it6. Istnieje konwersja tożsamości między każdą parą odpowiednich typów elementów, w tym zagnieżdżonych krotki, w związku z czym istnieje konwersja tożsamości między typami krotkit4,t5it6.przykład końcowy
Wszystkie konwersje tożsamości są symetryczne. Jeśli konwersja tożsamości istnieje z T₁ do T₂, konwersja tożsamości istnieje z T₂ do T₁. Dwa typy to tożsamość konwertowana , gdy istnieje konwersja tożsamości między dwoma typami.
W większości przypadków konwersja tożsamości nie ma wpływu na środowisko uruchomieniowe. Jednak ze względu na to, że operacje zmiennoprzecinkowe mogą być wykonywane z wyższą precyzją niż określona przez ich typ (§8.3.7), przypisanie ich wyników może spowodować utratę dokładności, a jawne rzutowania mają gwarancję zmniejszenia dokładności do tego, co jest zalecane przez typ (§12.9.8).
10.2.3 Niejawne konwersje liczbowe
Niejawne konwersje liczbowe to:
- Z
sbytedoshort, ,int,longfloat, ,doublelubdecimal. - Z
bytedoshort, ,ushortintuintlongulongfloatdoublelub .decimal - Z
shortdoint, ,longfloat, ,doublelubdecimal. - Z
ushortdoint, ,uintlongulongfloatdoublelub .decimal - Z
intdolong,float,doublelubdecimal. - Z
uintdolong, ,ulongfloat, ,doublelubdecimal. - Z
longdofloat,doublelubdecimal. - Z
ulongdofloat,doublelubdecimal. - Z
chardoushort, ,intuintlongulongfloat,doublelub .decimal - Od
floatdodouble.
Konwersje z int, lub uintlongulong do float i lub longulong mogą spowodować double utratę precyzji, ale nigdy nie spowodują utraty wielkości. Inne niejawne konwersje liczbowe nigdy nie tracą żadnych informacji.
Nie ma wstępnie zdefiniowanych konwersji niejawnych na char typ, więc wartości innych typów całkowitych nie są automatycznie konwertowane na char typ.
10.2.4 Niejawne konwersje wyliczenia
Niejawna konwersja wyliczenia zezwala na konwersję constant_expression (§12.25) z dowolnym typem całkowitym i wartością zero, która ma zostać przekonwertowana na dowolną enum_type i na dowolną nullable_value_type , której typem bazowym jest enum_type. W tym drugim przypadku konwersja jest obliczana przez przekonwertowanie na enum_type bazowych i zawijanie wyniku (§8.3.12).
10.2.5 Niejawne konwersje ciągów interpolowanych
Niejawna konwersja ciągów interpolowanych umożliwia konwersję interpolated_string_expression (§12.8.3
Po zastosowaniu tej konwersji wartość ciągu nie składa się z ciągu interpolowanego. Zamiast tego jest tworzone wystąpienie System.FormattableString , zgodnie z opisem w §12.8.3.
10.2.6 Niejawne konwersje dopuszczane do wartości null
Niejawne konwersje dopuszczane do wartości null to konwersje dopuszczane do wartości null (§10.6.1) pochodzące z niejawnych wstępnie zdefiniowanych konwersji.
Konwersje literałów null 10.2.7
Niejawna konwersja istnieje od null literału do dowolnego typu odwołania lub typu wartości dopuszczanej do wartości null. Ta konwersja tworzy odwołanie o wartości null, jeśli typ docelowy jest typem referencyjnym lub wartością null (§8.3.12) danego typu wartości dopuszczanej do wartości null.
10.2.8 Niejawne konwersje odwołań
Niejawne konwersje odwołań to:
- Z dowolnego reference_type do
objectidynamic. - Z dowolnego , podany
Sjest pochodzi z . - Z dowolnego , dostarczone
Simplementuje . - Z dowolnego , podany
Sjest pochodzi z . -
z typem
Selementu doSᵢz typemTelementu , pod warunkiem, że wszystkie następujące elementy są spełnione:-
SiTróżnią się tylko w typie elementu. Innymi słowy,SiTmają taką samą liczbę wymiarów. - Niejawna konwersja odwołania istnieje z
SᵢdoTᵢ.
-
- Z jednowymiarowego typu
S[]tablicy doSystem.Collections.Generic.IList<T>,System.Collections.Generic.IReadOnlyList<T>i ich interfejsów podstawowych, pod warunkiem, że istnieje niejawna tożsamość lub konwersja odwołania zSdoT. - Z dowolnego array_type do
System.Arrayinterfejsów, które implementuje. - Z dowolnego delegate_type do
System.Delegateinterfejsów, które implementuje. - Od literału null (§6.4.5.7) do dowolnego typu odwołania.
- Z dowolnego reference_type do , jeśli ma niejawną tożsamość lub konwersję odwołania do
TiT₀ma konwersję tożsamości naT₀. - Z dowolnego reference_type do interfejsu lub typu
Tdelegata, jeśli ma niejawną tożsamość lub konwersję odwołania do interfejsu lub typuT₀delegata iT₀jest wariancja-cabrio (§19.2.3.3) doT. - Niejawne konwersje obejmujące parametry typu, które są znane jako typy referencyjne. Aby uzyskać więcej informacji na temat niejawnych konwersji obejmujących parametry typu, zobacz §10.2.12 .
Niejawne konwersje odwołań to konwersje między reference_types, które można udowodnić, że zawsze się powiedzie, i dlatego nie wymagają żadnych kontroli w czasie wykonywania.
Konwersje odwołań, niejawne lub jawne, nigdy nie zmieniają tożsamości referencyjnej konwertowanego obiektu.
Uwaga: innymi słowy, podczas gdy konwersja odwołania może zmienić typ odwołania, nigdy nie zmienia typu lub wartości obiektu, do której jest odwoływany. notatka końcowa
Konwersje boksu 10.2.9
Konwersja boksu umożliwia niejawną konwersję value_type na reference_type. Istnieją następujące konwersje boksu:
- Z dowolnego value_type do typu
object. - Z dowolnego value_type do typu
System.ValueType. - Z dowolnego enum_type do typu
System.Enum. - Z dowolnego non_nullable_value_type do dowolnego interface_type zaimplementowanego przez non_nullable_value_type.
- Z dowolnego non_nullable_value_type do dowolnego interface_type
Itak, że istnieje konwersja boksu z non_nullable_value_type do innego interface_typeI₀iI₀ma konwersję tożsamości na .I - Od dowolnego non_nullable_value_type do dowolnego interface_type
Itak, że istnieje konwersja boksu z non_nullable_value_type do innego interface_typeI₀iI₀jest wariancja-cabrio (§19.2.3.3) doI. - Od dowolnego nullable_value_type do dowolnego reference_type, w którym istnieje konwersja boksu z bazowego typu nullable_value_type do reference_type.
- Z parametru typu, który nie jest znany jako typ odwołania do dowolnego typu, taki, że konwersja jest dozwolona przez §10.2.12.
Boxing wartość typu innej niż nullable-value składa się z przydzielania wystąpienia obiektu i kopiowania wartości do tego wystąpienia.
Boxing wartość nullable_value_type tworzy odwołanie o wartości null, jeśli jest to wartość null (HasValue jest fałsz) lub wynik rozpasania i tworzenia pola bazowej wartości w przeciwnym razie.
Uwaga: Proces tworzenia boksu można sobie wyobrazić pod względem istnienia klasy boksu dla każdego typu wartości. Rozważmy na przykład
struct Szaimplementowanie interfejsuIz klasą boksu o nazwieS_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 wartość
vtypuSskłada się teraz z wykonywania wyrażenianew S_Boxing(v)i zwracania wynikowego wystąpienia jako wartości typu docelowego konwersji. W związku z tym instrukcjeS s = new S(); object box = s;można traktować jako podobne do następujących:
S s = new S(); object box = new S_Boxing(s);Wyobrażany typ boksu opisany powyżej nie istnieje. Zamiast tego pole typu
Sma typ środowiska uruchomieniowego i sprawdzanie typuSśrodowiska uruchomieniowego przy użyciuisoperatora z typem wartości jako prawy operand testuje, czy lewy operand jest wersją pola prawego operandu. Na przykład:int i = 123; object box = i; if (box is int) { Console.Write("Box contains an int"); }polecenie zwróci następujące dane wyjściowe:
Box contains an intKonwersja boksu oznacza utworzenie kopii wartości w polu. Różni się to od konwersji reference_type na typ
object, w którym wartość nadal odwołuje się do tego samego wystąpienia i po prostu jest traktowana jako mniej pochodny typobject. Na przykład następujące elementystruct 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); } }spowoduje wygenerowanie wartości 10 w konsoli programu , ponieważ niejawna operacja boxingu wykonywana w przypisaniu
pboxpowoduje skopiowanie wartościp. ZamiastPointtegoclasszadeklarowano wartość 20, ponieważpiboxodwołuje się do tego samego wystąpienia.Analogia klasy boksu nie powinna być używana jako bardziej niż przydatne narzędzie do pikturowania sposobu działania boksu koncepcyjnie. Istnieje wiele subtelnych różnic między zachowaniem opisanym przez tę specyfikację a zachowaniem, które wynikałoby z implementacji boksu właśnie w ten sposób.
notatka końcowa
10.2.10 Niejawne konwersje dynamiczne
Niejawna konwersja dynamiczna istnieje z wyrażenia typu dynamicznego do dowolnego typu T. Konwersja jest dynamicznie powiązana §12.3.3, co oznacza, że niejawna konwersja będzie wyszukiwana w czasie wykonywania z typu czasu wykonywania wyrażenia na T. Jeśli nie znaleziono konwersji, zostanie zgłoszony wyjątek czasu wykonywania.
Ta niejawna konwersja pozornie narusza porady na początku §10.2 , że niejawna konwersja nigdy nie powinna powodować wyjątku. Nie jest to jednak sama konwersja, ale znalezienie konwersji powoduje wyjątek. Ryzyko wyjątków w czasie wykonywania jest związane z użyciem powiązania dynamicznego. Jeśli powiązanie dynamiczne konwersji nie jest pożądane, wyrażenie można najpierw przekonwertować na object, a następnie na żądany typ.
Przykład: Poniżej przedstawiono niejawne konwersje dynamiczne:
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 existsPrzypisania do
s2iioba stosują niejawne konwersje dynamiczne, w których powiązanie operacji jest zawieszone do czasu wykonywania. W czasie wykonywania wyszukiwane są niejawne konwersje typu czasudwykonywania (string) do typu docelowego. Znaleziono konwersję,stringale nie doint.przykład końcowy
10.2.11 Niejawne konwersje wyrażeń stałych
Niejawna konwersja wyrażenia stałego zezwala na następujące konwersje:
-
Typ constant_expression (§12.25)
intmożna przekonwertować na typsbyte,byteshortushortuintlubulong, pod warunkiem, że wartość constant_expression mieści się w zakresie typu docelowego. - Constant_expression typu
longmożna przekonwertować na typulong, pod warunkiem że wartość constant_expression nie jest ujemna.
10.2.12 Niejawne konwersje obejmujące parametry typu
, który jest znany jako typ odwołania (T), istnieją następujące niejawne konwersje odwołań (§10.2.8):
- Z
Tdo efektywnej klasyCbazowej , zTdo dowolnej klasy bazowejC, i zTdo dowolnego interfejsu zaimplementowanego przezC. - Od
Tdo interface_typezestawie interfejsów i zIdo dowolnego podstawowego interfejsuT. - Od
Tdo parametruUtypu, któryTzależyUod (§15.2.5).Uwaga: ponieważ
Tjest znany jako typ odwołania, w zakresieT, typUczasu wykonywania zawsze będzie typem odwołania, nawet jeśliUnie jest znany jako typ odwołania w czasie kompilacji. notatka końcowa - Od literału null (§6.4.5.7) do T.
W przypadku type_parameterT, który nie jest znany jako typ odwołania §15.2.5, następujące konwersje obejmujące T są uważane za konwersje boksu (§10.2.9) w czasie kompilacji. W czasie wykonywania, jeśli T jest typem wartości, konwersja jest wykonywana jako konwersja boksu. W czasie wykonywania, jeśli T jest typem odwołania, konwersja jest wykonywana jako niejawna konwersja odwołania lub konwersja tożsamości.
- Z
Tdo efektywnej klasyCbazowej , zTdo dowolnej klasy bazowejC, i zTdo dowolnego interfejsu zaimplementowanego przezC.Uwaga:
Cbędzie jednym z typówSystem.Object,System.ValueTypelubSystem.Enum(w przeciwnym razieTjest znany jako typ odwołania). notatka końcowa - Od
Tdo interface_typezestawie interfejsów i zIdo dowolnego podstawowego interfejsuT.
, który nieTznany jako typ odwołania, istnieje niejawna konwersja z do podanego T parametru U typu zależy od T. W czasie wykonywania, jeśli T jest typem wartości i U jest typem referencyjnym, konwersja jest wykonywana jako konwersja boksu. W czasie wykonywania, jeśli zarówno T typy wartości, jak i U są, i T muszą być tego samego typu i U nie jest wykonywana żadna konwersja. W czasie wykonywania, jeśli T jest typem odwołania, jest to koniecznie również typ odwołania, U a konwersja jest wykonywana jako niejawna konwersja odwołania lub konwersja tożsamości (§15.2.5).
Dla danego parametru Ttypu istnieją następujące dalsze niejawne konwersje:
- Od do typu
Todwołania, jeśli ma niejawną konwersję na typSodwołania iS₀ma konwersję tożsamości naS₀.SW czasie wykonywania konwersja jest wykonywana w taki sam sposób, jak konwersja naS₀. - Od
Tdo typuIinterfejsu, jeśli ma niejawną konwersję na typI₀interfejsu , iI₀jest wariancja-cabrio doI(§19.2.3.3). W czasie wykonywania, jeśliTjest typem wartości, konwersja jest wykonywana jako konwersja boksu. W przeciwnym razie konwersja jest wykonywana jako niejawna konwersja odwołania lub konwersja tożsamości.
We wszystkich przypadkach reguły zapewniają, że konwersja jest wykonywana jako konwersja boksu, jeśli i tylko wtedy, gdy w czasie wykonywania konwersja pochodzi z typu wartości do typu odwołania.
10.2.13 Niejawne konwersje krotki
Niejawna konwersja istnieje z wyrażenia E krotki na typ T krotki, jeśli E ma taką samą wartość, jak T i niejawna konwersja istnieje z każdego elementu w E do odpowiedniego typu elementu w .T Konwersja jest wykonywana przez utworzenie wystąpienia odpowiadającego TSystem.ValueTuple<...> mu typu i zainicjowanie każdego z jego pól w kolejności od lewej do prawej przez obliczenie odpowiedniego wyrażenia Eelementu krotki , przekonwertowanie go na odpowiedni typ T elementu przy użyciu znalezionej niejawnej konwersji i zainicjowanie pola z wynikiem.
Jeśli nazwa elementu w wyrażeniu krotki nie jest zgodna z odpowiednią nazwą elementu w typie krotki, zostanie wydane ostrzeżenie.
Przykład:
(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 ignoredDeklaracje
t1,t2t4it5są prawidłowe, ponieważ niejawne konwersje istnieją z wyrażeń elementów do odpowiednich typów elementów. Deklaracja elementu jest nieprawidłowat3, ponieważ nie ma konwersji znullnaint. Deklaracjat5powoduje ostrzeżenie, ponieważ nazwy elementów w wyrażeniu krotki różnią się od tych w typie krotki.przykład końcowy
10.2.14 Niejawne konwersje zdefiniowane przez użytkownika
Niejawna konwersja zdefiniowana przez użytkownika składa się z opcjonalnej standardowej niejawnej konwersji, a następnie wykonywania operatora niejawnej zdefiniowanej przez użytkownika, a następnie innej opcjonalnej standardowej niejawnej konwersji. Dokładne reguły oceny niejawnych konwersji zdefiniowanych przez użytkownika opisano w §10.5.4.
10.2.15 Konwersje funkcji anonimowych i konwersje grup metod
Funkcje anonimowe i grupy metod nie mają typów samodzielnie, ale mogą być niejawnie konwertowane na typy delegatów. Ponadto niektóre wyrażenia lambda mogą być niejawnie konwertowane na typy drzewa wyrażeń. Konwersje funkcji anonimowych opisano bardziej szczegółowo w temacie §10.7 i konwersji grup metod w §10.8.
10.2.16 Domyślne konwersje literałów
Niejawna konwersja istnieje z default_literal (§12.8.21) do dowolnego typu. Ta konwersja generuje wartość domyślną (§9.3) wnioskowanego typu.
10.2.17 Niejawne konwersje rzutów
Chociaż wyrażenia throw nie mają typu, mogą być niejawnie konwertowane na dowolny typ.
10.2.18 Konwersja wyrażeń przełącznika
Istnieje niejawna konwersja z switch_expression (§12.11) na każdy typT, dla którego istnieje niejawna konwersja z switch_expression_arm_expression każdego switch_expression_arm na T.
10.3 Konwersje jawne
10.3.1 Ogólne
Następujące konwersje są klasyfikowane jako konwersje jawne:
- Wszystkie niejawne konwersje (§10.2)
- Jawne konwersje liczbowe (§10.3.2)
- Jawne konwersje wyliczenia (§10.3.3)
- Jawne konwersje dopuszczane do wartości null (§10.3.4)
- Jawne konwersje krotki (§10.3.6)
- Jawne konwersje odwołań (§10.3.5)
- Jawne konwersje interfejsu
- Konwersje rozpatłaniania (§10.3.7)
- Jawne konwersje parametrów typu (§10.3.8)
- Jawne konwersje zdefiniowane przez użytkownika (§10.3.9)
Konwersje jawne mogą wystąpić w wyrażeniach rzutowych (§12.9.8).
Zestaw jawnych konwersji obejmuje wszystkie konwersje niejawne.
Uwaga: na przykład umożliwia użycie jawnego rzutowania, gdy istnieje niejawna konwersja tożsamości, aby wymusić wybór określonego przeciążenia metody. notatka końcowa
Jawne konwersje, które nie są niejawnymi konwersjami, to konwersje, których nie można udowodnić, że zawsze się powiedzie, konwersje, które są znane jako możliwe do utraty informacji, i konwersje między domenami typów wystarczająco różne, aby uzyskać jawną notację.
10.3.2 Jawne konwersje liczbowe
Jawne konwersje liczbowe to konwersje z numeric_type do innego numeric_type , dla którego niejawna konwersja liczbowa (§10.2.3) jeszcze nie istnieje:
- Z
sbytedobyte, ,ushortuint, ,ulonglubchar. - Od
bytedo lubsbytechar. - Z
shortdosbyte, ,byte,ushortuint, ,ulonglubchar. - Z
ushortdosbyte,byte,shortlubchar. - Z
intdosbyte, ,byteshortushortuintulonglub .char - Z
uintdosbyte, ,byte,shortushort, ,intlubchar. - Z
longdosbyte, ,byteshortushortintuint,ulonglub .char - Z
ulongdosbyte, ,byteshortushortintuint,longlub .char - Z
chardosbyte,bytelubshort. - Z
floatdosbyte,byte,shortushortintuintlongulong, ,charlub .decimal - Z
doubledosbyte, ,byteshortushortintuintlongulongcharfloatlub .decimal - Z
decimaldosbyte, ,byteshortushortintuintlongulongcharfloatlub .double
Ponieważ jawne konwersje obejmują wszystkie niejawne i jawne konwersje liczbowe, zawsze można przekonwertować z dowolnego numeric_type na inne numeric_type przy użyciu wyrażenia rzutowania (§12.9.8).
Jawne konwersje liczbowe mogą utracić informacje lub spowodować zgłaszanie wyjątków. Jawna konwersja liczbowa jest przetwarzana w następujący sposób:
- W przypadku konwersji typu całkowitego na inny typ całkowity przetwarzanie zależy od kontekstu sprawdzania przepełnienia (§12.8.20), w którym odbywa się konwersja:
-
checkedW kontekście konwersja powiedzie się, jeśli wartość operandu źródłowego mieści się w zakresie typu docelowego, ale zgłaszaSystem.OverflowExceptionwartość, jeśli wartość operandu źródłowego znajduje się poza zakresem typu docelowego. -
uncheckedW kontekście konwersja zawsze się powiedzie i będzie kontynuowana w następujący sposób.- Jeśli typ źródła jest większy niż typ docelowy, wartość źródłowa jest obcięta przez odrzucenie jego "dodatkowych" najbardziej znaczących bitów. Wynik jest następnie traktowany jako wartość typu docelowego.
- Jeśli typ źródła jest taki sam jak typ docelowy, wartość źródłowa jest traktowana jako wartość typu docelowego
-
- W przypadku konwersji z
decimalna typ całkowity wartość źródłowa jest zaokrąglona w kierunku zera do najbliższej wartości całkowitej, a ta wartość całkowita staje się wynikiem konwersji. Jeśli wynikowa wartość całkowita znajduje się poza zakresem typu docelowego, zwraca wartość .System.OverflowException - W przypadku konwersji z
floatlubdoublena typ całkowity przetwarzanie zależy od kontekstu sprawdzania przepełnienia (§12.8.20), w którym odbywa się konwersja:- W zaznaczonym kontekście konwersja jest kontynuowana w następujący sposób:
- Jeśli wartość operandu to NaN lub nieskończona,
System.OverflowExceptionjest zwracana wartość . - W przeciwnym razie operand źródłowy jest zaokrąglany w kierunku zera do najbliższej wartości całkowitej. Jeśli ta wartość całkowita znajduje się w zakresie typu docelowego, ta wartość jest wynikiem konwersji.
- W przeciwnym razie zgłaszany jest element
System.OverflowException.
- Jeśli wartość operandu to NaN lub nieskończona,
- W nieznakowanym kontekście konwersja zawsze się powiedzie i będzie kontynuowana w następujący sposób.
- Jeśli wartość operandu to NaN lub nieskończona, wynikiem konwersji jest nieokreślona wartość typu docelowego.
- W przeciwnym razie operand źródłowy jest zaokrąglany w kierunku zera do najbliższej wartości całkowitej. Jeśli ta wartość całkowita znajduje się w zakresie typu docelowego, ta wartość jest wynikiem konwersji.
- W przeciwnym razie wynik konwersji jest nieokreśloną wartością typu docelowego.
- W zaznaczonym kontekście konwersja jest kontynuowana w następujący sposób:
- W przypadku konwersji z
doublenafloatwartośćdoublewartość jest zaokrąglona do najbliższejfloatwartości.doubleJeśli wartość jest za mała, aby reprezentować jakofloatwartość , wynik stanie się zerowy z tym samym znakiem co wartość. Jeśli wielkośćdoublewartości jest zbyt duża, aby reprezentować jakofloatwartość , wynik staje się nieskończoność z tym samym znakiem co wartość.doubleJeśli wartość to NaN, wynik jest również wartością NaN. - W przypadku konwersji z lub na wartość źródłowa jest konwertowana na reprezentację i zaokrąglana do
floatnajbliższej liczby, jeśli jest to wymagane (double).decimaldecimal- Jeśli wartość źródłowa jest zbyt mała, aby reprezentować jako
decimalwartość , wynik staje się zerowy, zachowując znak oryginalnej wartości, jeślidecimalobsługuje wartości ze znakiem zero. - Jeśli wielkość wartości źródłowej jest zbyt duża, aby reprezentować wartość typu , lub ta wartość jest nieskończoność, wynik jest nieskończoność, zachowując znak oryginalnej wartości, jeśli reprezentacja dziesiętna obsługuje niedociągnienia
decimal; w przeciwnym razie zgłaszany jest wyjątek System.OverflowException. - Jeśli wartość źródłowa to NaN, wynik to NaN, jeśli reprezentacja dziesiętna obsługuje sieci NaNs; w przeciwnym razie zgłaszany jest wyjątek System.OverflowException.
- Jeśli wartość źródłowa jest zbyt mała, aby reprezentować jako
- W przypadku konwersji z
decimaldo lubfloatdoubledecimalwartość jest zaokrąglona do najbliższejdoublelubfloatwartości. Jeśli wielkość wartości źródłowej jest zbyt duża, aby reprezentować w typie docelowym lub ta wartość jest nieskończoność, wynik jest nieskończoność, zachowując znak oryginalnej wartości. Jeśli wartość źródłowa to NaN, wynik to NaN. Chociaż ta konwersja może utracić precyzję, nigdy nie powoduje zgłoszenia wyjątku.
Uwaga:
decimaltyp nie jest wymagany do obsługi wartości infiniacji ani wartości NaN, ale może to zrobić. Jego zakres może być mniejszy niż zakresfloatwartości idouble, ale nie jest gwarantowany. W przypadkudecimalreprezentacji bez wartości niedociągnięć lub wartości NaN i z zakresem mniejszym niżfloatwynik konwersji zdecimalnafloatalbodoublenigdy nie będzie nieskończoność lub NaN. notatka końcowa
10.3.3 Jawne konwersje wyliczenia
Jawne konwersje wyliczenia to:
- Z
sbyte, ,byteshortushortintuintlongulongcharfloatdoublelubdecimaldo dowolnej enum_type. - Z dowolnego enum_type do
sbyte,byte,shortushortintuintlongulongcharfloatdoublelub .decimal - Od dowolnego enum_type do innych enum_type.
Jawna konwersja wyliczenia między dwoma typami jest przetwarzana przez traktowanie wszystkich uczestniczących enum_type jako podstawowego typu tej enum_type, a następnie przeprowadzania niejawnej lub jawnej konwersji liczbowej między wynikowymi typami.
Przykład: biorąc pod uwagę enum_type
Ez podstawowym typemint, konwersja zEnabytejest przetwarzana jako jawna konwersja liczbowa (§10.3.2) zintdobyte, a konwersja zbytenaEjest przetwarzana jako niejawna konwersja liczbowa (§10.2.3) zbytedoint. przykład końcowy
10.3.4 Jawne konwersje dopuszczane do wartości null
Jawne konwersje dopuszczane do wartości null to konwersje dopuszczane do wartości null (§10.6.1) pochodzące z jawnych i niejawnych wstępnie zdefiniowanych konwersji.
10.3.5 Jawne konwersje odwołań
Jawne konwersje odwołań to:
- Od obiektu do innych reference_type.
- Z dowolnego , podana
Sjest klasą bazową . - Z dowolnego , dostarczone
Snie jest zapieczętowane i dostarczone nie implementuje .T - Z dowolnego , podany
Snie jest zapieczętowany ani dostarczany implementuje .T - Z dowolnego , podany
Snie pochodzi z . -
z typem
Selementu doSᵢz typemTelementu , pod warunkiem, że wszystkie następujące elementy są spełnione:-
SiTróżnią się tylko w typie elementu. Innymi słowy,SiTmają taką samą liczbę wymiarów. - Jawna konwersja odwołania istnieje z
SᵢdoTᵢ.
-
- Z
System.Arraypoziomu interfejsów, które implementuje, do dowolnego array_type. - Z jednowymiarowej array_type do , i jego interfejsów podstawowych, pod warunkiem, że istnieje konwersja tożsamości lub jawna konwersja odwołania z
S[]doSystem.Collections.Generic.IList<T>.System.Collections.Generic.IReadOnlyList<T>ST - Z
System.Collections.Generic.IList<S>,System.Collections.Generic.IReadOnlyList<S>i ich interfejsy podstawowe do jednowymiarowego typuT[]tablicy , pod warunkiem, że istnieje konwersja tożsamości lub jawna konwersja odwołania zSdo T. - Z
System.Delegateinterfejsów i implementuje do dowolnego delegate_type. - Od typu odwołania do typu
STodwołania, jeśli ma jawną konwersję odwołania zSdo typuT₀odwołania iT₀istnieje konwersja tożsamości zT₀naT. - Z typu
Sodwołania do interfejsu lub typuTdelegata, jeśli istnieje jawna konwersja odwołania zSdo interfejsu lub typuT₀delegata iT₀albo jest wariancja-cabrio doTlubTjest wariancja-cabrio doT₀§19.2.3.3. - Od
D<S₁...Sᵥ>lokalizacji, gdzieD<T₁...Tᵥ>D<X₁...Xᵥ>jest ogólnym typem delegata,D<S₁...Sᵥ>nie jest zgodny z lub identycznyD<T₁...Tᵥ>z parametrem , i dla każdego parametruXᵢtypu następującegoDblokady:- Jeśli
Xᵢzmienna jest niezmienna,Sᵢwartość jest taka sama jakTᵢ. - Jeśli
Xᵢjest kowariantny, istnieje konwersja tożsamości, niejawna konwersja odwołania lub jawna konwersja odwołania zSᵢdoTᵢ. - Jeśli
Xᵢjest kontrawariantny, toSᵢiTᵢsą identyczne lub oba typy odwołań.
- Jeśli
- Jawne konwersje obejmujące parametry typu, które są znane jako typy odwołań. Aby uzyskać więcej informacji na temat jawnych konwersji obejmujących parametry typu, zobacz §10.3.8.
Jawne konwersje odwołań to konwersje między reference_types, które wymagają kontroli czasu wykonywania, aby upewnić się, że są poprawne.
Aby jawna konwersja referencyjna zakończyła się powodzeniem w czasie wykonywania, wartość operandu źródłowego wynosi null, lub typ obiektu, do którego odwołuje się operand źródłowy, jest typem, który można przekonwertować na typ docelowy przez niejawną konwersję odwołania (§10.2.8). Jeśli jawna konwersja odwołania zakończy się niepowodzeniem System.InvalidCastException , zostanie zgłoszony wyjątek .
Uwaga: Konwersje odwołań, niejawne lub jawne, nigdy nie zmieniają wartości samego odwołania (§8.2.1), tylko jego typu; ani nie zmienia typu ani wartości obiektu, do których odwołuje się odwołanie. notatka końcowa
10.3.6 Jawne konwersje krotki
Jawna konwersja istnieje z wyrażenia E krotki na typ T krotki, jeśli E ma taką samą wartość, jak T i niejawna lub jawna konwersja istnieje z każdego elementu w E obiekcie do odpowiedniego typu elementu w T. Konwersja jest wykonywana przez utworzenie wystąpienia odpowiadającego TSystem.ValueTuple<...> mu typu i zainicjowanie każdego z jego pól w kolejności od lewej do prawej przez obliczenie odpowiedniego wyrażenia Eelementu krotki , przekonwertowanie go na odpowiedni typ T elementu przy użyciu znalezionej jawnej konwersji i zainicjowanie pola z wynikiem.
10.3.7 Konwersje rozpatłaniania
Konwersja rozpakowania umożliwia jawną konwersję reference_type na value_type. Istnieją następujące konwersje rozpakowania:
- Od typu
objectdo dowolnego value_type. - Od typu
System.ValueTypedo dowolnego value_type. - Od typu
System.Enumdo dowolnego enum_type. - Z dowolnego interface_type do dowolnego non_nullable_value_type, który implementuje interface_type.
- Z dowolnego , w którym istnieje konwersja rozpboxowania z interface_type do
Ii konwersja tożsamości z na .I₀ - Z dowolnego interface_type do dowolnego
I, w którym istnieje konwersja rozpakowa z interface_typeI₀do non_nullable_value_type iI₀jest variance_convertible doIlubIjest wariancja-kabriolet doI₀(§19.2.3.3). - Z dowolnego reference_type do dowolnego nullable_value_type, w którym istnieje konwersja rozpboxowania z reference_type do bazowej non_nullable_value_type nullable_value_type.
- Z parametru typu, który nie jest znany jako typ wartości do dowolnego typu, taki, że konwersja jest dozwolona przez §10.3.8.
Operacja rozpychania do non_nullable_value_type polega na pierwszym sprawdzeniu, czy wystąpienie obiektu jest wartością w polu danego non_nullable_value_type, a następnie skopiowaniem wartości z wystąpienia.
Odpakowywanie do nullable_value_type powoduje wygenerowanie wartości null nullable_value_type , jeśli operand źródłowy to null, lub otokowany wynik odłączenia wystąpienia obiektu do bazowego typu nullable_value_type w przeciwnym razie.
Uwaga: Odwołując się do wyimaginowanej klasy boksu opisanej w §10.2.9, konwersja pola obiektu na value_type
Sskłada się z wykonywania wyrażenia((S_Boxing)box).value. W związku z tym instrukcjeobject box = new S(); S s = (S)box;koncepcyjnie odpowiadają
object box = new S_Boxing(new S()); S s = ((S_Boxing)box).value;notatka końcowa
W przypadku konwersji rozpychanej na daną non_nullable_value_type pomyślnej w czasie wykonywania wartość operandu źródłowego jest odwołaniem do wartości pola tej non_nullable_value_type. Jeśli argument argumentu źródłowego null jest System.NullReferenceException zgłaszany. Jeśli operand źródłowy jest odwołaniem do niezgodnego obiektu, System.InvalidCastException zgłaszany jest argument .
W przypadku konwersji rozpychania na daną nullable_value_type pomyślnej w czasie wykonywania wartość operandu źródłowego musi mieć wartość null lub odwołanie do wartości pola bazowej non_nullable_value_typenullable_value_type. Jeśli operand źródłowy jest odwołaniem do niezgodnego obiektu, System.InvalidCastException zgłaszany jest argument .
10.3.8 Jawne konwersje obejmujące parametry typu
Dla type_parameterT, który jest znany jako typ odwołania (§15.2.5), istnieją następujące jawne konwersje odwołań (§10.3.5):
- Od efektywnej klasy
Cbazowej doTi z dowolnej klasy bazowejTCdoTklasy . - Z dowolnego interface_type do
T. - Od
Tdo dowolnego interface_typeIpod warunkiem, że nie ma jeszcze niejawnej konwersji odwołania zTdoI. -
do
Upodanego, żeTzależy odT(U).Uwaga: ponieważ
Tjest znany jako typ odwołania, w zakresieT, typ czasu wykonywania zawsze będzie typem odwołania, nawet jeśliUnie jest znany jako typ odwołania w czasie kompilacji. notatka końcowa
W przypadku type_parameterT, który nie jest znany jako typ odwołania (§15.2.5), następujące konwersje obejmujące T są uważane za konwersje rozpałkania (§10.3.7) w czasie kompilacji. W czasie wykonywania, jeśli T jest typem wartości, konwersja jest wykonywana jako konwersja rozpakłania. W czasie wykonywania, jeśli T jest typem odwołania, konwersja jest wykonywana jako jawna konwersja odwołania lub konwersja tożsamości.
- Od efektywnej klasy
Cbazowej doTi z dowolnej klasy bazowejTCdoTklasy .Uwaga: C będzie jednym z typów
System.Object,System.ValueTypelubSystem.Enum(w przeciwnym razieTbędzie znany jako typ odwołania). notatka końcowa - Z dowolnego interface_type do
T.
, który nieTznany jako typ odwołania (§15.2.5), istnieją następujące jawne konwersje:
- Od
Tdo dowolnego interface_typeIpod warunkiem, że nie ma jeszcze niejawnej konwersji zTdoI. Ta konwersja składa się z niejawnej konwersji boksu (§10.2.9) zTdoobject, po której następuje jawna konwersja odwołania zobjectdoI. W czasie wykonywania, jeśliTjest typem wartości, konwersja jest wykonywana jako konwersja boksu, po której następuje jawna konwersja odwołania. W czasie wykonywania, jeśliTjest typem odwołania, konwersja jest wykonywana jako jawna konwersja odwołania. - Od parametru
Utypu doTpodanego, któryTzależyUod (§15.2.5). W czasie wykonywania, jeśliTjest typem wartości iUjest typem referencyjnym, konwersja jest wykonywana jako konwersja rozpieczętowana. W czasie wykonywania, jeśli zarównoTtypy wartości, jak iUsą, iTmuszą być tego samego typu iUnie jest wykonywana żadna konwersja. W czasie wykonywania, jeśliTjest typem odwołania,Umusi być również typem odwołania, a konwersja jest wykonywana jako jawna konwersja referencyjna lub konwersja tożsamości.
We wszystkich przypadkach reguły zapewniają, że konwersja jest wykonywana jako konwersja rozpętywania, jeśli i tylko wtedy, gdy w czasie wykonywania konwersja pochodzi z typu odwołania do typu wartości.
Powyższe reguły nie zezwalają na bezpośrednią jawną konwersję z parametru typu bez ograniczeń do typu innego niż interfejs, co może być zaskakujące. Przyczyną tej reguły jest zapobieganie nieporozumieniu i czyszczenie semantyki takich konwersji.
Przykład: Rozważ następującą deklarację:
class X<T> { public static long F(T t) { return (long)t; // Error } }Jeśli dozwolona jest bezpośrednia jawna konwersja elementu
t,longmożna łatwo oczekiwać, żeX<int>.F(7)zwróci7Lwartość . Jednak nie byłoby tak, ponieważ standardowe konwersje liczbowe są brane pod uwagę tylko wtedy, gdy typy są znane jako liczbowe w czasie powiązania. Aby semantyka było jasne, zamiast tego należy napisać powyższy przykład:class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }Ten kod zostanie teraz skompilowany, ale wykonanie
X<int>.F(7)spowoduje zgłoszenie wyjątku w czasie wykonywania, ponieważ nie można przekonwertować polaintbezpośrednio nalongelement .przykład końcowy
10.3.9 Jawne konwersje zdefiniowane przez użytkownika
Jawna konwersja zdefiniowana przez użytkownika składa się z opcjonalnej standardowej jawnej konwersji, a następnie wykonywania niejawnego lub jawnego operatora konwersji zdefiniowanego przez użytkownika, a następnie innej opcjonalnej standardowej jawnej konwersji. Dokładne reguły oceny jawnych konwersji zdefiniowanych przez użytkownika opisano w §10.5.5.
Konwersje standardowe 10.4
10.4.1 Ogólne
Konwersje standardowe to wstępnie zdefiniowane konwersje, które mogą wystąpić w ramach konwersji zdefiniowanej przez użytkownika.
10.4.2 Standardowe konwersje niejawne
Następujące niejawne konwersje są klasyfikowane jako standardowe konwersje niejawne:
- Konwersje tożsamości (§10.2.2)
- Niejawne konwersje liczbowe (§10.2.3)
- Niejawne konwersje dopuszczane do wartości null (§10.2.6)
- Konwersje literału null (§10.2.7)
- Niejawne konwersje odwołań (§10.2.8)
- Konwersje boksu (§10.2.9)
- Niejawne konwersje wyrażeń stałych (§10.2.11)
- Niejawne konwersje obejmujące parametry typu (§10.2.12)
Standardowe konwersje niejawne wykluczają konwersje niejawne zdefiniowane przez użytkownika.
10.4.3 Standardowe konwersje jawne
Standardowe konwersje jawne to wszystkie standardowe konwersje niejawne oraz podzbiór jawnych konwersji, dla których istnieje odwrotna standardowa niejawna konwersja.
Uwaga: innymi słowy, jeśli istnieje standardowa niejawna konwersja typu na typ
AB, standardowa jawna konwersja istnieje z typu na typABi od typuBdo typuA. notatka końcowa
10.5 Konwersje zdefiniowane przez użytkownika
10.5.1 Ogólne
Język C# umożliwia wstępnie zdefiniowane niejawne i jawne konwersje rozszerzone przez konwersje zdefiniowane przez użytkownika. Konwersje zdefiniowane przez użytkownika są wprowadzane przez deklarowanie operatorów konwersji (§15.10.4) w typach klas i struktur.
10.5.2 Dozwolone konwersje zdefiniowane przez użytkownika
Język C# zezwala na deklarowanie tylko niektórych konwersji zdefiniowanych przez użytkownika. W szczególności nie można ponownie zdefiniować istniejącej niejawnej lub jawnej konwersji.
Dla danego typu źródłowego i typu STdocelowego , jeśli S lub T są typami wartości dopuszczania wartości null, pozwól S₀ i T₀ odwołaj się do ich typów bazowych, w przeciwnym razie S₀ i T₀ są równe S i T odpowiednio. Klasa lub struktura może zadeklarować konwersję z typu źródłowego na typ ST docelowy tylko wtedy, gdy spełnione są wszystkie następujące elementy:
-
S₀iT₀są różnymi typami. - Albo
S₀jest klasą lubT₀typem struktury, w którym odbywa się deklaracja operatora. - Ani nie
S₀T₀jest interface_type. - Wykluczanie konwersji zdefiniowanych przez użytkownika, konwersja nie istnieje z
SdoTlub zTdoS.
Ograniczenia dotyczące konwersji zdefiniowanych przez użytkownika są określone w §15.10.4.
10.5.3 Ocena konwersji zdefiniowanych przez użytkownika
Konwersja zdefiniowana przez użytkownika konwertuje wyrażenie źródłowe, które może mieć typ źródłowy, na inny typ nazywany typem docelowym. Ocena zdefiniowanego przez użytkownika centrum konwersji w celu znalezienia najbardziej określonego operatora konwersji zdefiniowanego przez użytkownika dla wyrażenia źródłowego i typu docelowego. Ta determinacja jest podzielona na kilka kroków:
- Znajdowanie zestawu klas i struktur, z których będą brane pod uwagę operatory konwersji zdefiniowane przez użytkownika. Ten zestaw składa się z typu źródłowego i jego klas bazowych, jeśli typ źródłowy istnieje, wraz z typem docelowym i jego klasami podstawowymi. W tym celu zakłada się, że tylko klasy i struktury mogą deklarować operatory zdefiniowane przez użytkownika, a typy nieklasowe nie mają klas bazowych. Ponadto jeśli typ źródłowy lub docelowy jest typem wartości null, używany jest ich typ bazowy.
- Z tego zestawu typów określ, które operatory konwersji zdefiniowane przez użytkownika i zniesione mają zastosowanie. Aby operator konwersji mógł mieć zastosowanie, możliwe jest przeprowadzenie konwersji standardowej (§10.4) od wyrażenia źródłowego do typu operand operatora i możliwe jest przeprowadzenie standardowej konwersji z typu wyniku operatora na typ docelowy.
- Z zestawu odpowiednich operatorów zdefiniowanych przez użytkownika, określając, który operator jest jednoznacznie najbardziej specyficzny. Ogólnie rzecz biorąc, najbardziej specyficznym operatorem jest operator, którego typ operandu jest "najbliżej" wyrażenia źródłowego i którego typ wyniku jest "najbliżej" typu docelowego. Operatory konwersji zdefiniowane przez użytkownika są preferowane przez operatory konwersji zniesionej. Dokładne reguły ustanawiania najbardziej specyficznego operatora konwersji zdefiniowanego przez użytkownika są zdefiniowane w następujących podklasach.
Po zidentyfikowaniu najbardziej określonego operatora konwersji zdefiniowanego przez użytkownika rzeczywiste wykonanie konwersji zdefiniowanej przez użytkownika obejmuje maksymalnie trzy kroki:
- Najpierw, jeśli jest to wymagane, wykonanie standardowej konwersji z wyrażenia źródłowego na typ operandu zdefiniowanego przez użytkownika lub operatora konwersji zniesionej.
- Następnie wywołanie zdefiniowanego przez użytkownika lub zniesionego operatora konwersji w celu przeprowadzenia konwersji.
- Na koniec, jeśli jest to wymagane, wykonanie standardowej konwersji z typu wyniku operatora konwersji zdefiniowanego przez użytkownika na typ docelowy.
Ocena konwersji zdefiniowanej przez użytkownika nigdy nie obejmuje więcej niż jednego operatora konwersji zdefiniowanego przez użytkownika lub zniesionego. Innymi słowy konwersja typu na typ ST nigdy nie będzie najpierw wykonywać konwersji zdefiniowanej przez użytkownika z S do X , a następnie wykonać konwersję zdefiniowaną przez użytkownika z X na T.
- Dokładne definicje oceny niejawnych lub jawnych konwersji zdefiniowanych przez użytkownika są podane w następujących podklasach. Definicje korzystają z następujących terminów:
- Jeśli standardowa niejawna konwersja (§10.4.2) istnieje z typu
Ado typuB, a jeśli aniA, aniBnie są interface_types, mówi się, żeAjest objęte przezB, aBmówi się, że obejmowaćA. - Jeśli standardowa konwersja niejawna (§10.4.2) istnieje z wyrażenia
Edo typuB, a jeśli aniB, ani typuE(jeśli ma) są interface_types, mówi się, żeEjest objęteB, aBmówi się, że obejmująE. - Najbardziej obejmującym typem zestawu typów jest jeden typ, który obejmuje wszystkie inne typy w zestawie. Jeśli żaden pojedynczy typ nie obejmuje wszystkich innych typów, zestaw nie ma najbardziej obejmującego typu. W bardziej intuicyjnych kategoriach najbardziej obejmujący typ to "największy" typ zestawu — jeden typ, do którego można niejawnie konwertować poszczególne typy.
- Najbardziej obejmującym typ zestawu typów jest jednym typem obejmującym wszystkie inne typy w zestawie. Jeśli żaden pojedynczy typ nie jest uwzględniany przez wszystkie inne typy, zestaw nie ma najbardziej objętego typu. W bardziej intuicyjnych kategoriach najbardziej obejmujący typ jest "najmniejszym" typem w zestawie — jednym typem, który może być niejawnie konwertowany na każdy z innych typów.
10.5.4 Niejawne konwersje zdefiniowane przez użytkownika
Zdefiniowana przez użytkownika niejawna konwersja z wyrażenia E na typ T jest przetwarzana w następujący sposób:
Określanie typów
S,S₀iT₀.- Jeśli
Ema typ, niechSbędzie to typ. - Jeśli
SlubTsą typami wartości dopuszczania wartości null, niechSᵢiTᵢbędą ich podstawowymi typami, w przeciwnym razie letSᵢiTᵢbeSiT, odpowiednio. - Jeśli
SᵢlubTᵢsą parametrami typu, let i be ich efektywne klasy bazowe, w przeciwnym razie letS₀T₀iS₀beT₀iSᵢTᵢ, odpowiednio.
- Jeśli
Znajdź zestaw typów ,
Dz którego zostaną uwzględnione operatory konwersji zdefiniowane przez użytkownika. Ten zestaw składa się zS₀(jeśliS₀istnieje i jest klasą lub strukturą), klas bazowychS₀(jeśliS₀istnieje i jest klasą) orazT₀(jeśliT₀jest klasą lub strukturą). Typ jest dodawany do zestawuDtylko wtedy, gdy konwersja tożsamości na inny typ już uwzględniony w zestawie nie istnieje.Znajdź zestaw odpowiednich operatorów konwersji zdefiniowanych przez użytkownika i zniesionych,
U. Ten zestaw składa się z zdefiniowanych przez użytkownika i podniesionych niejawnych operatorów konwersji zadeklarowanych przez klasy lub struktury wDtej konwersji z typu obejmującego typ obejmujący typ obejmującyEprzezTelement . JeśliUjest pusty, konwersja jest niezdefiniowana i występuje błąd czasu kompilacji.Znajdź najbardziej specyficzny typ źródła,
Sₓ, operatorów w plikuU:- Jeśli
Sistnieje i którykolwiek z operatorów wUkonwersji zS, toSₓjestS. -
SₓW przeciwnym razie jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych operatorów w programieU. Jeśli nie można odnaleźć dokładnie jednego najbardziej objętego typu, konwersja jest niejednoznaczna i wystąpi błąd czasu kompilacji.
- Jeśli
Znajdź najbardziej specyficzny typ docelowy,
Tₓ, operatorów w plikuU:- Jeśli którykolwiek z operatorów w
Ukonwersji naT, toTₓma wartośćT. -
TₓW przeciwnym razie jest najbardziej obejmującym typem w połączonym zestawie typów docelowych operatorów w systemieU. Jeśli nie można odnaleźć dokładnie jednego typu obejmującego, konwersja jest niejednoznaczna i występuje błąd czasu kompilacji.
- Jeśli którykolwiek z operatorów w
Znajdź najbardziej specyficzny operator konwersji:
- Jeśli
Uzawiera dokładnie jeden operator konwersji zdefiniowany przez użytkownika, który konwertujeSₓz naTₓ, jest to najbardziej specyficzny operator konwersji. - W przeciwnym razie, jeśli
Uzawiera dokładnie jeden operator konwersji zniesionej, który konwertuje zSₓnaTₓ, jest to najbardziej specyficzny operator konwersji. - W przeciwnym razie konwersja jest niejednoznaczna i występuje błąd czasu kompilacji.
- Jeśli
Na koniec zastosuj konwersję:
- Jeśli E nie ma jeszcze typu
Sₓ, wykonywana jest standardowa niejawna konwersja zEdoSₓ. - Najbardziej specyficzny operator konwersji jest wywoływany w celu konwersji z
SₓnaTₓ. - Jeśli
TₓnieTma wartości , wykonywana jest standardowa niejawna konwersja zTₓdoT.
- Jeśli E nie ma jeszcze typu
Zdefiniowana przez użytkownika niejawna konwersja z typu S na typ T istnieje, jeśli zdefiniowana przez użytkownika niejawna konwersja istnieje ze zmiennej typu S na T.
10.5.5 Jawne konwersje zdefiniowane przez użytkownika
Zdefiniowana przez użytkownika jawna konwersja z wyrażenia E na typ T jest przetwarzana w następujący sposób:
- Określanie typów
S,S₀iT₀.- Jeśli
Ema typ, niechSbędzie to typ. - Jeśli
SlubTsą typami wartości dopuszczania wartości null, niechSᵢiTᵢbędą ich podstawowymi typami, w przeciwnym razie letSᵢiTᵢbeSiT, odpowiednio. - Jeśli
SᵢlubTᵢsą parametrami typu, let i be ich efektywne klasy bazowe, w przeciwnym razie letS₀T₀iS₀beT₀iSᵢTᵢ, odpowiednio.
- Jeśli
- Znajdź zestaw typów ,
Dz którego zostaną uwzględnione operatory konwersji zdefiniowane przez użytkownika. Ten zestaw składa się zS₀(jeśliS₀istnieje i jest klasą lub strukturą), klas bazowychS₀(jeśliS₀istnieje i jest klasą),T₀(jeśliT₀jest klasą lub strukturą) oraz klasamiT₀bazowymi (jeśliT₀jest klasą). Typ jest dodawany do zestawuDtylko wtedy, gdy konwersja tożsamości na inny typ już uwzględniony w zestawie nie istnieje. - Znajdź zestaw odpowiednich operatorów konwersji zdefiniowanych przez użytkownika i zniesionych,
U. Ten zestaw składa się z zdefiniowanych przez użytkownika i podniesionych niejawnych lub jawnych operatorów konwersji zadeklarowanych przez klasy lub struktury wDtej konwersji z typu obejmującego lubEobjętegoS(jeśli istnieje) do typu obejmującego lub objętego przezTprogram . JeśliUjest pusty, konwersja jest niezdefiniowana i występuje błąd czasu kompilacji. - Znajdź najbardziej specyficzny typ źródła,
Sₓ, operatorów w plikuU:- Jeśli S istnieje i którykolwiek z operatorów w
Ukonwersji zS, toSₓjestS. - W przeciwnym razie, jeśli którykolwiek z operatorów w
Ukonwersji z typów, które obejmująE,Sₓjest najbardziej obejmującym typem w połączonym zestawie typów źródłowych tych operatorów. Jeśli nie można odnaleźć najbardziej objętego typu, konwersja jest niejednoznaczna i wystąpi błąd czasu kompilacji. -
SₓW przeciwnym razie jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych operatorów w systemieU. Jeśli nie można odnaleźć dokładnie jednego typu obejmującego, konwersja jest niejednoznaczna i występuje błąd czasu kompilacji.
- Jeśli S istnieje i którykolwiek z operatorów w
- Znajdź najbardziej specyficzny typ docelowy,
Tₓ, operatorów w plikuU:- Jeśli którykolwiek z operatorów w
Ukonwersji naT, toTₓma wartośćT. - W przeciwnym razie, jeśli którykolwiek z operatorów w
Ukonwersji na typy, które są objęte przezT,Tₓjest najbardziej obejmującym typem w połączonym zestawie typów docelowych tych operatorów. Jeśli nie można odnaleźć dokładnie jednego typu obejmującego, konwersja jest niejednoznaczna i występuje błąd czasu kompilacji. -
TₓW przeciwnym razie jest najbardziej obejmującym typem w połączonym zestawie typów docelowych operatorów w systemieU. Jeśli nie można odnaleźć najbardziej objętego typu, konwersja jest niejednoznaczna i wystąpi błąd czasu kompilacji.
- Jeśli którykolwiek z operatorów w
- Znajdź najbardziej specyficzny operator konwersji:
- Jeśli U zawiera dokładnie jednego operatora konwersji zdefiniowanego przez użytkownika, który konwertuje
Sₓz naTₓ, jest to najbardziej specyficzny operator konwersji. - W przeciwnym razie, jeśli
Uzawiera dokładnie jeden operator konwersji zniesionej, który konwertuje zSₓnaTₓ, jest to najbardziej specyficzny operator konwersji. - W przeciwnym razie konwersja jest niejednoznaczna i występuje błąd czasu kompilacji.
- Jeśli U zawiera dokładnie jednego operatora konwersji zdefiniowanego przez użytkownika, który konwertuje
- Na koniec zastosuj konwersję:
- Jeśli
Enie ma jeszcze typuSₓ, wykonywana jest standardowa jawna konwersja z E naSₓ. - Najbardziej specyficzny operator konwersji zdefiniowany przez użytkownika jest wywoływany w celu konwersji z
SₓnaTₓ. - Jeśli
TₓnieTma wartości , wykonywana jest standardowa jawna konwersja zTₓdoT.
- Jeśli
Jawna konwersja zdefiniowana przez użytkownika z typu na typ ST istnieje, jeśli zdefiniowana przez użytkownika jawna konwersja istnieje ze zmiennej typu S na T.
10.6 Konwersje obejmujące typy dopuszczane do wartości null
Konwersje dopuszczane do wartości null 10.6.1
Konwersja dopuszczana do wartości null umożliwia wstępnie zdefiniowaną konwersję, która działa na typie wartości innej niż null, która ma być również używana z formą dopuszczającą wartość null tego typu. Dla każdej wstępnie zdefiniowanej niejawnej lub jawnej konwersji, która konwertuje z typu wartości niepustej na typ ST wartości niepustej (§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 i §10.3.3), istnieją następujące konwersje dopuszczające wartość null:
- Niejawna lub jawna konwersja z
S?doT? - Niejawna lub jawna konwersja z
SdoT? - Jawna konwersja z
S?naT.
Konwersja dopuszczana do wartości null jest klasyfikowana jako niejawna lub jawna konwersja.
Niektóre konwersje dopuszczane do wartości null są klasyfikowane jako konwersje standardowe i mogą wystąpić w ramach konwersji zdefiniowanej przez użytkownika. W szczególności wszystkie niejawne konwersje dopuszczające wartość null są klasyfikowane jako standardowe konwersje niejawne (§10.4.2), a te jawne konwersje dopuszczające wartość null spełniające wymagania §10.4.3 są klasyfikowane jako standardowe konwersje jawne.
Ocena konwersji dopuszczanej do wartości null na podstawie konwersji bazowej z S do T następuje w następujący sposób:
- Jeśli konwersja dopuszczana do wartości null jest z
S?doT?:- Jeśli wartość źródłowa ma wartość null (
HasValuewłaściwość tofalse), wynikiem jest wartość null typuT?. - W przeciwnym razie konwersja jest obliczana jako rozpasanie z
S?doS, a następnie konwersja bazowa zSnaT, a następnie zawijanie zTdoT?.
- Jeśli wartość źródłowa ma wartość null (
- Jeśli konwersja dopuszczana do wartości null pochodzi z
Sdo , konwersja jest obliczana jako konwersja bazowa zT?do, po której następuje zawijanie zSdoTT.T? - Jeśli konwersja dopuszczana do wartości null wynosi od
S?do , konwersja jest obliczana jako rozpasanie zTdo, po której następuje konwersja bazowa zS?naSS.T
10.6.2 Konwersje zniesione
Biorąc pod uwagę zdefiniowany przez użytkownika operator konwersji, który konwertuje typ wartości S innej niż null na typ Twartości innej niż null, istnieje operator konwersji zniesionej, który konwertuje wartość z S? na T?. Ten operator zniesionej konwersji wykonuje odpisanie z S? doS, po którym następuje konwersja zdefiniowana przez użytkownika z S na, po której następuje zawijanie z T do TT? , z tą różnicą, że wartość S? null konwertuje bezpośrednio na wartość null.T? Operator konwersji zniesionej ma taką samą niejawną lub jawną klasyfikację jak jego podstawowy operator konwersji zdefiniowany przez użytkownika.
Konwersje funkcji anonimowych 10.7
10.7.1 Ogólne
Anonymous_method_expression lub lambda_expression jest klasyfikowana jako funkcja anonimowa (§12.21). Wyrażenie nie ma typu, ale może być niejawnie konwertowane na zgodny typ delegata. Niektóre wyrażenia lambda mogą być również niejawnie konwertowane na zgodny typ drzewa wyrażeń.
W szczególności funkcja F anonimowa jest zgodna z typem D delegata podanym:
- Jeśli
Fzawiera anonymous_function_signature, toDiFmają taką samą liczbę parametrów. - Jeśli
Fnie zawiera anonymous_function_signature,Dmoże mieć zero lub więcej parametrów dowolnego typu, o ile żaden parametr nie jest parametremDwyjściowym. - Jeśli
Fma jawnie wpisaną listę parametrów, każdy parametr w programieDma te same modyfikatory co odpowiedni parametr wFprogramie, a konwersja tożsamości istnieje między odpowiednim parametrem wFpliku . - Jeśli
Fma niejawnie typizowane listy parametrów,Dnie ma żadnych parametrów referencyjnych ani wyjściowych. - Jeśli treść
Fjest wyrażeniem iDma typ zwracany void lubFjest asynchroniczny iDma«TaskType»typ zwracany (§15.14.1), to kiedy każdy parametrFma typ odpowiadającego mu parametru wD, treśćFjest prawidłowym wyrażeniem (w.r.t §12), które byłoby dozwolone jako statement_expression (§13.7). - Jeśli treść obiektu jest blokiem i
Fma typ zwracany void lubDzwracany , wówczas, gdy każdy parametr ma typ odpowiedniego parametruFwD, treść«TaskType»Fjest prawidłowym blokiem (w.r.tD), w którym żadna instrukcja nieFokreśla wyrażenia. - Jeśli treść
Fjest wyrażeniem, a alboFnie jest asynchroniczna iDma inny typ zwracanyvoid,Tjest asynchroniczna iFmaDtyp zwracany («TaskType»<T>), wtedy gdy każdy parametr otrzymuje typ odpowiadającego parametru wF, treśćDjest prawidłowym wyrażeniem (wzgl. §12), które jest niejawnie konwertowane naF. - Jeśli treść obiektu jest blokiem i
Falbo nie jest asynchroniczny iFma niepusty typDzwracany ,Tjest asynchroniczny iFma typ zwracany, gdy każdy parametrDjest podany typ odpowiedniego parametru w«TaskType»<T>, treśćFDjest prawidłowym blokiem instrukcji (w.r.tF) z nieosiągalnym punktem końcowym, w którym każda instrukcja return określa wyrażenie, które jest niejawnie konwertowane na .T
Przykład: Następujące przykłady ilustrują następujące reguły:
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"; };przykład końcowy
Przykład: Przykłady, które korzystają z ogólnego typu
Func<A,R>delegata, który reprezentuje funkcję, która przyjmuje argument typuAi zwraca wartość typuR:delegate R Func<A,R>(A arg);W przydziałach
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 i zwracane typy każdej funkcji anonimowej są określane z typu zmiennej, do której przypisano funkcję anonimową.
Pierwsze przypisanie pomyślnie konwertuje funkcję anonimową na typ
Func<int,int>delegata, ponieważ w przypadkuxdanego typuintx + 1jest prawidłowe wyrażenie niejawnie konwertowane na typint.Podobnie drugie przypisanie pomyślnie konwertuje funkcję anonimową na typ delegata Func<int,dwukrotnie> , ponieważ wynik
x + 1(typuint) jest niejawnie konwertowany na typdouble.Jednak trzecie przypisanie jest błędem czasu kompilacji, ponieważ w przypadku
xdanego typudoublewynikx + 1(typudouble) nie jest niejawnie konwertowany na typint.Czwarte przypisanie pomyślnie konwertuje anonimową funkcję asynchronicznie na typ
Func<int, Task<int>>delegata, ponieważ wynikx + 1(typuint) jest niejawnie konwertowany na efektywny typintzwracany asynchronicznego lambda, który ma typTask<int>zwracany .przykład końcowy
Wyrażenie F lambda jest zgodne z typem Expression<D> drzewa wyrażeń, jeśli F jest zgodne z typem Ddelegata . Nie dotyczy to metod anonimowych, tylko wyrażeń lambda.
Funkcje anonimowe mogą mieć wpływ na rozpoznawanie przeciążenia i uczestniczyć w wnioskowaniu typu. Aby uzyskać więcej informacji, zobacz §12.6 .
10.7.2 Ocena konwersji funkcji anonimowych na typy delegatów
Konwersja funkcji anonimowej na typ delegata powoduje wystąpienie delegata, które odwołuje się do funkcji anonimowej i (prawdopodobnie puste) zestawu przechwyconych zmiennych zewnętrznych, które są aktywne w czasie oceny. Po wywołaniu delegata jest wykonywana treść funkcji anonimowej. Kod w treści jest wykonywany przy użyciu zestawu przechwyconych zmiennych zewnętrznych, do których odwołuje się delegat. Można użyć delegate_creation_expression (§12.8.17.5) jako alternatywnej składni do konwertowania metody anonimowej na typ delegata.
Lista wywołań delegata wygenerowanego z funkcji anonimowej zawiera pojedynczy wpis. Dokładny obiekt docelowy i metoda docelowa delegata nie są określone. W szczególności nie określono, czy obiekt docelowy delegata to null, this wartość otaczającego elementu członkowskiego funkcji lub inny obiekt.
Konwersje semantycznie identycznych funkcji anonimowych z tym samym (prawdopodobnie pustym) zestawem przechwyconych wystąpień zmiennych zewnętrznych do tych samych typów delegatów są dozwolone (ale nie są wymagane) do zwrócenia tego samego wystąpienia delegata. Termin semantycznie identyczny jest używany w tym miejscu, aby oznaczać, że wykonanie funkcji anonimowych w każdym przypadku spowoduje wygenerowanie tych samych efektów, biorąc pod uwagę te same argumenty. Ta reguła zezwala na optymalizację kodu, takiego jak poniższe.
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));
...
}
}
Ponieważ dwa delegaty funkcji anonimowej mają ten sam (pusty) zbiór przechwyconych zewnętrznych zmiennych, a funkcje anonimowe są semantycznie identyczne, kompilator może pozwolić, aby delegaty odwoływały się do tej samej metody docelowej. Rzeczywiście, kompilator może zwrócić tę samą instancję delegata z obu wyrażeń anonimowych funkcji.
10.7.3 Ocena konwersji wyrażeń lambda na typy drzewa wyrażeń
Konwersja wyrażenia lambda na typ drzewa wyrażeń powoduje utworzenie drzewa wyrażeń (§8.6). Dokładniej mówiąc, ocena konwersji wyrażenia lambda generuje strukturę obiektu reprezentującą strukturę samego wyrażenia lambda.
Nie każde wyrażenie lambda można przekonwertować na typy drzewa wyrażeń. Konwersja na zgodny typ delegata zawsze istnieje, ale może zakończyć się niepowodzeniem w czasie kompilacji ze względów zdefiniowanych przez implementację.
Uwaga: typowe przyczyny niepowodzenia konwersji wyrażenia lambda na typ drzewa wyrażeń obejmują:
- Ma ciało bloku
- Ma
asyncmodyfikator- Zawiera operator przypisania
- Zawiera on parametr wyjściowy lub referencyjny
- Zawiera wyrażenie dynamicznie powiązane
notatka końcowa
Konwersje grup metod 10.8
Niejawna konwersja istnieje z grupy metod (§12.2) do zgodnego typu delegata (§21.4). Jeśli D jest typem delegata i E jest wyrażeniem, które jest klasyfikowane jako grupa metod, jest D zgodne z if i tylko wtedy, gdy E zawiera co najmniej jedną metodę, która ma zastosowanie w postaci normalnej (E) do dowolnej listy argumentów (§12.6.2) o typach i modyfikatorach pasujących do typów parametrów i modyfikatorów , zgodnie z D opisem w poniższym artykule.
Zastosowanie konwersji w czasie kompilacji z grupy E metod do typu D delegata zostało opisane w poniższym artykule.
- Wybrana jest pojedyncza metoda odpowiadająca wywołaniu metody
M(§12.8.10.2) formularzaE(A)z następującymi modyfikacjami:- Lista
Aargumentów jest listą wyrażeń, z których każda jest klasyfikowana jako zmienna i z typem i modyfikatorem (in,outlubref) odpowiedniego parametru w parameter_listD— z wyjątkiem parametrów typudynamic, gdzie odpowiadające wyrażenie ma typobjectzamiastdynamic. - Rozważane metody kandydata to tylko te metody, które mają zastosowanie w ich normalnej postaci i nie pomijają żadnych parametrów opcjonalnych (§12.6.4.2). W związku z tym metody kandydatów są ignorowane, jeśli mają zastosowanie tylko w rozszerzonym formularzu, lub jeśli co najmniej jeden z parametrów opcjonalnych nie ma odpowiedniego parametru w pliku
D.
- Lista
- Konwersja jest uważana za istniejącą, jeśli algorytm §12.8.10.2 tworzy jedną najlepszą metodę
Mzgodną (§21.4) zD. - Jeśli wybrana metoda
Mjest metodą wystąpienia, wyrażenie wystąpienia skojarzone zEokreśla obiekt docelowy delegata. - Jeśli wybrana metoda
Mjest metodą rozszerzenia, która jest oznaczona za pomocą dostępu do elementu członkowskiego w wyrażeniu wystąpienia, to wyrażenie wystąpienia określa obiekt docelowy delegata. - Wynikiem konwersji jest wartość typu
D, a mianowicie delegat odwołujący się do wybranej metody i obiektu docelowego.
Przykład: Poniżej przedstawiono konwersje grup 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 } }Przypisanie niejawnie
d1konwertuje grupęFmetod na wartość typuD1.Przypisanie
d2pokazuje, w jaki sposób można utworzyć delegata do metody, która ma mniej pochodne (kontrawariantne) typy parametrów i bardziej pochodny (kowariantny) typ zwracany.Przypisanie pokazuje
d3, jak nie istnieje konwersja, jeśli metoda nie ma zastosowania.Przypisanie, aby pokazać
d4, jak metoda musi być stosowana w postaci normalnej.Przypisanie w celu pokazania
d5, jak typy parametrów i zwracanych delegatów i metod mogą się różnić tylko dla typów odwołań.przykład końcowy
Podobnie jak w przypadku wszystkich innych niejawnych i jawnych konwersji, operator rzutowania może służyć do jawnego wykonania określonej konwersji.
Przykład: W związku z tym przykład
object obj = new EventHandler(myDialog.OkClick);zamiast tego można napisać
object obj = (EventHandler)myDialog.OkClick;przykład końcowy
Konwersja grupy metod może odwoływać się do metody ogólnej, jawnie określając argumenty typu w obiekcie Elub za pośrednictwem wnioskowania typu (§12.6.3). Jeśli jest używana wnioskowanie typu, typy parametrów delegata są używane jako typy argumentów w procesie wnioskowania. Zwracany typ delegata nie jest używany do wnioskowania. Niezależnie od tego, czy argumenty typu są określone, czy wnioskowane, są częścią procesu konwersji grupy metod; są to argumenty typu używane do wywoływania metody docelowej podczas wywoływania wynikowego delegata.
Przykład:
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 } }przykład końcowy
Grupy metod mogą mieć wpływ na rozpoznawanie przeciążenia i uczestniczyć w wnioskowaniu typów. Aby uzyskać więcej informacji, zobacz §12.6 .
Ocena czasu wykonywania konwersji grupy metod jest kontynuowana w następujący sposób:
- Jeśli metoda wybrana w czasie kompilacji jest metodą wystąpienia lub jest metodą rozszerzenia, która jest dostępna jako metoda wystąpienia, obiekt docelowy delegata jest określany na podstawie wyrażenia wystąpienia skojarzonego z
E:- Wyrażenie wystąpienia jest obliczane. Jeśli ta ocena powoduje wyjątek, nie są wykonywane żadne dalsze kroki.
- Jeśli wyrażenie wystąpienia jest reference_type, wartość obliczona przez wyrażenie wystąpienia staje się obiektem docelowym. Jeśli wybrana metoda jest metodą wystąpienia, a obiektem docelowym jest
null,System.NullReferenceExceptionjest zgłaszany i nie są wykonywane żadne dalsze kroki. - Jeśli wyrażenie wystąpienia jest value_type, operacja boksu (§10.2.9) jest wykonywana w celu przekonwertowania wartości na obiekt, a ten obiekt staje się obiektem docelowym.
- W przeciwnym razie wybrana metoda jest częścią wywołania metody statycznej, a obiektem docelowym delegata jest
null. - Wystąpienie delegata typu
Ddelegata jest uzyskiwane przy użyciu odwołania do metody określonej w czasie kompilacji i odwołania do obiektu docelowego obliczonego powyżej w następujący sposób:- Konwersja jest dozwolona (ale nie jest wymagana) do użycia istniejącego wystąpienia delegata, które zawiera już te odwołania.
- Jeśli istniejące wystąpienie nie zostało ponownie użyte, zostanie utworzony nowy (§21.5). Jeśli nie ma wystarczającej ilości pamięci do przydzielenia nowego wystąpienia,
System.OutOfMemoryExceptionzgłaszany jest błąd . W przeciwnym razie wystąpienie jest inicjowane przy użyciu podanych odwołań.
ECMA C# draft specification