10 conversies
10.1 Algemeen
Een conversie zorgt ervoor dat een expressie wordt geconverteerd naar of behandeld als een bepaald type. In het eerste geval kan een conversie een wijziging in de weergave omvatten. Conversies kunnen impliciet of expliciet zijn en dit bepaalt of een expliciete cast vereist is.
Voorbeeld: de conversie van type
int
naar typelong
is bijvoorbeeld impliciet, zodat expressies van het typeint
impliciet als typelong
kunnen worden behandeld. De tegenovergestelde conversie, van typelong
naar typeint
, is expliciet en dus is een expliciete cast vereist.int a = 123; long b = a; // implicit conversion from int to long int c = (int) b; // explicit conversion from long to int
eindvoorbeeld
Sommige conversies worden gedefinieerd door de taal. Programma's kunnen ook hun eigen conversies definiëren (§10,5).
Sommige conversies in de taal worden gedefinieerd van expressies tot typen, andere van typen tot typen. Een conversie van een type is van toepassing op alle expressies met dat type.
Voorbeeld:
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;
eindvoorbeeld
10.2 Impliciete conversies
10.2.1 Algemeen
De volgende conversies worden geclassificeerd als impliciete conversies:
- Identiteitsconversies (§10.2.2)
- Impliciete numerieke conversies (§10.2.3)
- Impliciete opsommingsconversies (§10.2.4)
- Impliciete geïnterpoleerde tekenreeksconversies (§10.2.5)
- Impliciete verwijzingsconversies (§10.2.8)
- Boksen conversies (§10.2.9)
- Impliciete dynamische conversies (§10.2.10)
- Impliciete parameterconversies van type (§10.2.12)
- Impliciete conversie van constante expressies (§10.2.11)
- Door de gebruiker gedefinieerde (inclusief opgeheven) impliciete conversies (§10.2.14)
- Anonieme functieconversies (§10.2.15)
- Methodegroepconversies (§10.2.15)
- Null-letterlijke conversies (§10.2.7)
- Impliciete null-conversies (§10.2.6)
- Impliciete tupleconversies (§10.2.13)
- Standaard letterlijke conversies (§10.2.16)
- Impliciete conversies van gooien (§10.2.17)
Impliciete conversies kunnen in verschillende situaties optreden, waaronder functielid-aanroepen (§12.6.6), cast-expressies (§12.9.7) en toewijzingen (§12.21).
De vooraf gedefinieerde impliciete conversies slagen altijd en veroorzaken nooit dat uitzonderingen worden gegenereerd.
Opmerking: Goed ontworpen door de gebruiker gedefinieerde impliciete conversies moeten ook deze kenmerken vertonen. eindnotitie
Voor conversie zijn de typen object
converteerbaar dynamic
(§10.2.2).
Dynamische conversies (§10.2.10) zijn echter alleen van toepassing op expressies van het type dynamic
(§8.2.4).
10.2.2 Identiteitsconversie
Een identiteitsconversie wordt geconverteerd van elk type naar hetzelfde type of een type dat tijdens runtime gelijkwaardig is. Een van de redenen dat deze conversie bestaat, is dat een type T
of een expressie van het type T
kan worden gezegd om converteerbaar te zijn naar T
zichzelf. De volgende identiteitsconversies bestaan:
- Tussen
T
enT
, voor elk typeT
. - Tussen
T
enT?
voor elk verwijzingstypeT
. - Tussen
object
endynamic
. - Tussen alle tupletypen met dezelfde arity en het bijbehorende samengestelde
ValueTuple<...>
type, wanneer er een identiteitsconversie bestaat tussen elk paar overeenkomende elementtypen. - Tussen typen die zijn samengesteld uit hetzelfde algemene type, waarbij er een identiteitsconversie bestaat tussen elk bijbehorend typeargument.
Voorbeeld: Hieronder ziet u de recursieve aard van de derde regel:
(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;
De typen tuples
t1
ent2
t3
hebben allemaal twee elementen: eenint
gevolgd door eenstring
. Tuple-elementtypen kunnen zichzelf door tuples, zoals int4
,t5
ent6
. Er bestaat een identiteitsconversie tussen elk paar bijbehorende elementtypen, inclusief geneste tuples, waardoor er een identiteitsconversie bestaat tussen de typen tuplest4
,t5
ent6
.eindvoorbeeld
Alle identiteitsconversies zijn symmetrisch. Als er een identiteitsconversie van T₁
naar T₂
bestaat, bestaat er een identiteitsconversie van T₂
naar T₁
. Twee typen zijn converteerbare identiteiten wanneer er een identiteitsconversie tussen twee typen bestaat.
In de meeste gevallen heeft een identiteitsconversie geen effect tijdens runtime. Aangezien drijvendekommabewerkingen echter met een hogere precisie kunnen worden uitgevoerd dan voorgeschreven door hun type (§8.3.7), kan de toewijzing van hun resultaten leiden tot een verlies van precisie en expliciete casts zijn gegarandeerd om de precisie te beperken tot wat wordt voorgeschreven door het type (§12.9.7).
10.2.3 Impliciete numerieke conversies
De impliciete numerieke conversies zijn:
- Van
sbyte
naarshort
,int
,long
, , ,float
ofdouble
decimal
. - Van
byte
naarshort
,ushort
, ,int
,uint
, ,long
,ulong
, ,float
, ,double
ofdecimal
. - Van
short
naarint
,long
,float
, ofdouble
decimal
. - Van
ushort
naarint
,uint
,long
, ,ulong
, ,float
, ofdouble
.decimal
- Van
int
naarlong
,float
, ofdouble
decimal
. - Van
uint
naarlong
,ulong
,float
, ofdouble
decimal
. - Van
long
naarfloat
,double
ofdecimal
. - Van
ulong
naarfloat
,double
ofdecimal
. - Van
char
naarushort
,int
, ,uint
,long
, ,ulong
, ,float
, ,double
ofdecimal
. - Van
float
indouble
.
Conversies vanint
, uint
long
of van en ulong
float
naar long
of ulong
naar double
kunnen leiden tot verlies van precisie, maar zullen nooit een verlies van grootte veroorzaken. De andere impliciete numerieke conversies verliezen nooit informatie.
Er zijn geen vooraf gedefinieerde impliciete conversies naar het char
type, dus waarden van de andere integrale typen worden niet automatisch geconverteerd naar het char
type.
10.2.4 Impliciete opsommingsconversies
Met een impliciete opsommingsconversie kan een constant_expression (§12.23) met een geheel getal en de waarde nul worden geconverteerd naar een enum_type en naar een nullable_value_type waarvan het onderliggende type een enum_type is. In het laatste geval wordt de conversie geëvalueerd door te converteren naar de onderliggende enum_type en het resultaat te verpakken (§8.3.12).
10.2.5 Impliciete geïnterpoleerde tekenreeksconversies
Met een impliciete geïnterpoleerde tekenreeksconversie kan een interpolated_string_expression (§12.8.3System.FormattableString
System.IFormattable
Wanneer deze conversie wordt toegepast, wordt een tekenreekswaarde niet samengesteld uit de geïnterpoleerde tekenreeks. In plaats daarvan wordt er een exemplaar van System.FormattableString
gemaakt, zoals verder beschreven in §12.8.3.
10.2.6 Impliciete null-conversies
De impliciete null-conversies zijn de conversies die nullable zijn (§10.6.1) die zijn afgeleid van impliciete vooraf gedefinieerde conversies.
10.2.7 Null-letterlijke conversies
Er bestaat een impliciete conversie van de null
letterlijke waarde naar een verwijzingstype of null-waardetype. Deze conversie produceert een null-verwijzing als het doeltype een verwijzingstype is of de null-waarde (§8.3.12) van het opgegeven type null-waarde.
10.2.8 Impliciete verwijzingsconversies
De impliciete verwijzingsconversies zijn:
- Van elke reference_type tot
object
endynamic
. - Van elke class_type
S
tot een class_typeT
, dieS
wordt verstrekt, is afgeleid vanT
. - Van elke class_type
S
tot elke interface_typeT
, geleverdS
implementeertT
. - Van elke interface_type
S
tot een interface_typeT
, dieS
wordt verstrekt, is afgeleid vanT
. - Van een array_type
S
met een elementtypeSᵢ
tot een array_typeT
met een elementtypeTᵢ
, mits alle volgende waar zijn:-
S
enT
verschilt alleen in elementtype. Met andere woorden,S
enT
hebben hetzelfde aantal dimensies. - Er bestaat een impliciete verwijzingsconversie van
Sᵢ
naarTᵢ
.
-
- Van een enkeldimensionaal matrixtype
S[]
naarSystem.Collections.Generic.IList<T>
,System.Collections.Generic.IReadOnlyList<T>
en de bijbehorende basisinterfaces, mits er een impliciete identiteit of verwijzingsconversie vanS
naarT
. - Van elke array_type naar
System.Array
en de interfaces die worden geïmplementeerd. - Van elke delegate_type naar
System.Delegate
en de interfaces die worden geïmplementeerd. - Van de letterlijke waarde null (§6.4.5.7) tot elk verwijzingstype.
- Van elke reference_type naar een reference_type
T
als deze een impliciete identiteit of verwijzingsconversie heeft naar eenT₀
enT₀
een identiteitsconversieT
naar . - Van elke reference_type naar een interface of gedelegeerd type
T
als deze een impliciete identiteit of verwijzingsconversie heeft naar een interface of gedelegeerd typeT₀
enT₀
variantie-converteerbaar is (§18.2.3.3) naarT
. - Impliciete conversies met typeparameters die bekend zijn als referentietypen. Zie §10.2.12 voor meer informatie over impliciete conversies met betrekking tot typeparameters.
De impliciete verwijzingsconversies zijn die conversies tussen reference_types die kunnen worden bewezen altijd te slagen en daarom geen controles tijdens runtime vereisen.
Verwijzingsconversies, impliciet of expliciet, wijzigen nooit de referentiële identiteit van het object dat wordt geconverteerd.
Opmerking: Met andere woorden, terwijl een verwijzingsconversie het type van de verwijzing kan wijzigen, wordt nooit het type of de waarde van het object waarnaar wordt verwezen, gewijzigd. eindnotitie
10.2.9 Boksing conversies
Met een boksconversie kan een value_type impliciet worden geconverteerd naar een reference_type. De volgende boksconversies bestaan:
- Van elke value_type tot het type
object
. - Van elke value_type tot het type
System.ValueType
. - Van elke enum_type tot het type
System.Enum
. - Van elke non_nullable_value_type tot alle interface_type die door de non_nullable_value_type zijn geïmplementeerd.
- Van elke
I
- Van elke non_nullable_value_type tot elke
I
zodanig dat er een boksconversie van de non_nullable_value_type naar een andereI₀
, enI₀
is variantie-converteerbaar (§18.2.3.3) totI
. - Van elke nullable_value_type naar een reference_type waar een boksconversie van het onderliggende type van de nullable_value_type naar de reference_type is.
- Van een typeparameter die niet bekend is als referentietype voor elk type, zodat de conversie is toegestaan door §10.2.12.
Het boksen van een waarde die niet nullable is, bestaat uit het toewijzen van een objectexemplaar en het kopiëren van de waarde naar dat exemplaar.
Als u een waarde van een nullable_value_type boksen, wordt een null-verwijzing gegenereerd als dit de null-waarde is (HasValue
onwaar) of het resultaat van het uitpakken en boksen van de onderliggende waarde, anders.
Opmerking: Het boksproces kan worden voorgesteld in termen van het bestaan van een boksklasse voor elk waardetype. Denk bijvoorbeeld aan een
struct S
implementatie van een interfaceI
, met een boksklasse genaamdS_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(); } }
Het boksen van een waarde
v
van het typeS
bestaat nu uit het uitvoeren van de expressienew S_Boxing(v)
en het retourneren van het resulterende exemplaar als een waarde van het doeltype van de conversie. De verklaringenS s = new S(); object box = s;
kan worden beschouwd als vergelijkbaar met:
S s = new S(); object box = new S_Boxing(s);
Het hierboven beschreven type boksen bestaat niet daadwerkelijk. In plaats daarvan heeft een waarde in een vak van het type
S
het runtimetypeS
en een runtimetypecontrole met behulp van deis
operator met een waardetype als de rechteroperand test of de linkeroperand een vakkenversie van de rechteroperand is. Bijvoorbeeld:int i = 123; object box = i; if (box is int) { Console.Write("Box contains an int"); }
voert het volgende uit:
Box contains an int
Een boksconversie impliceert het maken van een kopie van de waarde die in een vak wordt geplaatst. Dit verschilt van een conversie van een
object
. Bijvoorbeeld: het volgendestruct 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); } }
voert de waarde 10 uit op de console omdat de impliciete boksbewerking die plaatsvindt in de toewijzing van
p
debox
waarde diep
moet worden gekopieerd, wordt uitgevoerd. WasPoint
een in plaats daarvan gedeclareerdclass
, de waarde 20 zou uitvoer zijn omdatp
enbox
zou verwijzen naar hetzelfde exemplaar.De analogie van een boksklasse mag niet worden gebruikt als meer dan een nuttig hulpmiddel voor het weergeven van hoe boksen werkt conceptueel. Er zijn talloze subtiele verschillen tussen het gedrag dat door deze specificatie wordt beschreven en het gedrag dat zou resulteren uit boksen op precies deze manier.
eindnotitie
10.2.10 Impliciete dynamische conversies
Er bestaat een impliciete dynamische conversie van een expressie van het type dynamisch naar elk type T
. De conversie is dynamisch gebonden §12.3.3, wat betekent dat een impliciete conversie wordt gezocht tijdens runtime vanaf het uitvoeringstype van de expressie naar T
. Als er geen conversie wordt gevonden, wordt er een runtime-uitzondering gegenereerd.
Deze impliciete conversie schendt schijnbaar het advies in het begin van §10.2 dat een impliciete conversie nooit een uitzondering mag veroorzaken. Het is echter niet de conversie zelf, maar het vinden van de conversie die de uitzondering veroorzaakt. Het risico van runtime-uitzonderingen is inherent aan het gebruik van dynamische binding. Als dynamische binding van de conversie niet gewenst is, kan de expressie eerst worden geconverteerd naar object
en vervolgens naar het gewenste type.
Voorbeeld: Hieronder ziet u impliciete dynamische conversies:
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 exists
De toewijzingen aan
s2
eni
beide maken gebruik van impliciete dynamische conversies, waarbij de binding van de bewerkingen wordt onderbroken tot de runtime. Tijdens runtime worden impliciete conversies gezocht van het runtimetype vand
(string
) naar het doeltype. Er wordt een conversie gevonden naarstring
, maar niet naarint
.eindvoorbeeld
10.2.11 Impliciete constante expressieconversies
Een impliciete conversie van constante expressies maakt de volgende conversies mogelijk:
- Een constant_expression (§12.23) van het type
int
kan worden geconverteerd naar typesbyte
, ,byte
short
ushort
, ,uint
ofulong
, mits de waarde van de constant_expression binnen het bereik van het doeltype valt. - Een constant_expression van het type kan worden geconverteerd naar het type
long
ulong
, mits de waarde van de constant_expression niet negatief is.
10.2.12 Impliciete conversies met typeparameters
Voor een T
die bekend staat als referentietype (§15.2.5), bestaan de volgende impliciete verwijzingsconversies (§10.2.8):
- Van
T
tot de effectieve basisklasseC
, vanT
naar elke basisklasse vanC
en vanT
elke interface die wordt geïmplementeerd doorC
. - Van
T
naar een interface_typeI
inT
de effectieve interfaceset en vanT
elke basisinterface vanI
. - Van
T
naar een typeparameterU
dieT
afhankelijkU
is van (§15.2.5).Opmerking: Aangezien
T
bekend is dat het een verwijzingstype is,T
is het runtimetypeU
altijd een referentietype, zelfs alsU
het niet bekend is dat het een verwijzingstype tijdens het compileren is. eindnotitie - Van de letterlijke waarde null (§6.4.5.7) tot T.
Voor een T
die niet bekend is als referentietype §15.2.5, worden de volgende conversies T
beschouwd als boksconversies (§10.2.9) tijdens het compileren. Als dit een waardetype is, T
wordt de conversie tijdens runtime uitgevoerd als boksconversie. Als dit een verwijzingstype is, T
wordt de conversie tijdens runtime uitgevoerd als een impliciete verwijzingsconversie of identiteitsconversie.
- Van
T
tot de effectieve basisklasseC
, vanT
naar elke basisklasse vanC
en vanT
elke interface die wordt geïmplementeerd doorC
.Opmerking:
C
dit is een van de typenSystem.Object
,System.ValueType
ofSystem.Enum
(andersT
zou het een verwijzingstype zijn). eindnotitie - Van
T
naar een interface_typeI
inT
de effectieve interfaceset en vanT
elke basisinterface vanI
.
Voor een type_parameterT
die niet bekend is als een verwijzingstype, is er een impliciete conversie van T
naar een typeparameter U
opgegevenT
, afhankelijk U
van.
T
Als dit een waardetype is en U
een verwijzingstype is, wordt de conversie uitgevoerd als een boksconversie. Tijdens runtime, als beide T
en U
waardetypen zijn, T
en U
noodzakelijkerwijs hetzelfde type zijn en er geen conversie wordt uitgevoerd. Als dit een verwijzingstype is, T
U
is dit noodzakelijkerwijs ook een referentietype en wordt de conversie uitgevoerd als impliciete verwijzingsconversie of identiteitsconversie (§15.2.5).
De volgende impliciete conversies bestaan voor een bepaalde typeparameter T
:
- Van
T
naar een verwijzingstypeS
als het een impliciete conversie naar een verwijzingstypeS₀
heeft enS₀
een identiteitsconversieS
naar . Tijdens de uitvoering wordt de conversie op dezelfde manier uitgevoerd als de conversie naarS₀
. - Van
T
naar een interfacetypeI
als deze een impliciete conversie naar een interfacetypeI₀
heeft enI₀
variantie converteert naarI
(§18.2.3.3). Als dit een waardetype is,T
wordt de conversie tijdens runtime uitgevoerd als boksconversie. Anders wordt de conversie uitgevoerd als een impliciete verwijzingsconversie of identiteitsconversie.
In alle gevallen zorgen de regels ervoor dat een conversie wordt uitgevoerd als een boksconversie als en alleen als de conversie tijdens runtime van een waardetype naar een verwijzingstype is.
10.2.13 Impliciete tupleconversies
Een impliciete conversie bestaat van een tuple-expressie E
naar een tupletype T
als E
dezelfde arity heeft als T
en een impliciete conversie bestaat van elk element in E
het bijbehorende elementtype in T
. De conversie wordt uitgevoerd door een exemplaar van T
het bijbehorende System.ValueTuple<...>
type te maken en elk van de velden te initialiseren in volgorde van links naar rechts door de bijbehorende tuple-elementexpressie te evalueren, E
te converteren naar het bijbehorende elementtype van het gebruik van T
de impliciete conversie gevonden en het veld te initialiseren met het resultaat.
Als een elementnaam in de tuple-expressie niet overeenkomt met een overeenkomende elementnaam in het tuple-type, wordt een waarschuwing afgegeven.
Voorbeeld:
(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
De declaraties van
t1
,t2
t4
ent5
zijn allemaal geldig, omdat impliciete conversies bestaan van de elementexpressies naar de bijbehorende elementtypen. De declaratie vant3
is ongeldig, omdat er geen conversie is vannull
naarint
. De declaratie vant5
veroorzaakt een waarschuwing omdat de elementnamen in de tuple-expressie verschillen van die in het tuple-type.eindvoorbeeld
10.2.14 Door de gebruiker gedefinieerde impliciete conversies
Een door de gebruiker gedefinieerde impliciete conversie bestaat uit een optionele standaard impliciete conversie, gevolgd door de uitvoering van een door de gebruiker gedefinieerde impliciete conversieoperator, gevolgd door een andere optionele standaard impliciete conversie. De exacte regels voor het evalueren van door de gebruiker gedefinieerde impliciete conversies worden beschreven in §10.5.4.
10.2.15 Anonieme functieconversies en methodegroepconversies
Anonieme functies en methodegroepen hebben geen typen in en van zichzelf, maar ze kunnen impliciet worden geconverteerd naar gedelegeerde typen. Daarnaast kunnen sommige lambda-expressies impliciet worden geconverteerd naar expressiestructuurtypen. Anonieme functieconversies worden uitgebreid beschreven in §10.7 en methodegroepconversies in §10.8.
10.2.16 Standaard letterlijke conversies
Er bestaat een impliciete conversie van een default_literal (§12.8.21) tot elk type. Deze conversie produceert de standaardwaarde (§9.3) van het uitgestelde type.
10.2.17 Impliciete conversies voor gooien
Hoewel throw-expressies geen type hebben, kunnen ze impliciet worden geconverteerd naar elk type.
10.3 Expliciete conversies
10.3.1 Algemeen
De volgende conversies worden geclassificeerd als expliciete conversies:
- Alle impliciete conversies (§10.2)
- Expliciete numerieke conversies (§10.3.2)
- Expliciete opsommingsconversies (§10.3.3)
- Expliciete null-conversies (§10.3.4)
- Expliciete tupleconversies (§10.3.6)
- Expliciete verwijzingsconversies (§10.3.5)
- Expliciete interfaceconversies
- Conversies uitpakken (§10.3.7)
- Expliciete typeparameterconversies (§10.3.8)
- Door de gebruiker gedefinieerde expliciete conversies (§10.3.9)
Expliciete conversies kunnen optreden in cast-expressies (§12.9.7).
De set expliciete conversies bevat alle impliciete conversies.
Opmerking: Hiermee kan bijvoorbeeld een expliciete cast worden gebruikt wanneer er een impliciete identiteitsconversie bestaat, om de selectie van een bepaalde methode overbelast te houden. eindnotitie
De expliciete conversies die geen impliciete conversies zijn, zijn conversies die niet altijd kunnen worden bewezen, conversies die mogelijk informatie verliezen en conversies tussen typen voldoende verschillend zijn om expliciete notatie te verdienen.
10.3.2 Expliciete numerieke conversies
De expliciete numerieke conversies zijn de conversies van een numeric_type naar een andere numeric_type waarvoor een impliciete numerieke conversie (§10.2.3) nog niet bestaat:
- Van
sbyte
naarbyte
,ushort
,uint
, ofulong
char
. - Van
byte
naarsbyte
ofchar
. - Van
short
naarsbyte
,byte
,ushort
, , ,uint
ofulong
char
. - Van
ushort
naarsbyte
,byte
, ofshort
char
. - Van
int
naarsbyte
,byte
,short
, ,ushort
, ,uint
, ofulong
.char
- Van
uint
naarsbyte
,byte
,short
, , ,ushort
ofint
char
. - Van
long
naarsbyte
,byte
, ,short
,ushort
, ,int
, ,uint
, ,ulong
ofchar
. - Van
ulong
naarsbyte
,byte
, ,short
,ushort
, ,int
, ,uint
, ,long
ofchar
. - Van
char
naarsbyte
,byte
ofshort
. - Van
float
naarsbyte
,byte
, ,short
,ushort
, ,int
,uint
, ,long
,ulong
, , , ,char
ofdecimal
. - Van
double
naarsbyte
,byte
, ,short
,ushort
, ,int
uint
,long
, ,ulong
,char
, , offloat
decimal
. - Van
decimal
naarsbyte
,byte
, ,short
,ushort
, ,int
uint
,long
, ,ulong
,char
, , offloat
double
.
Omdat de expliciete conversies alle impliciete en expliciete numerieke conversies bevatten, is het altijd mogelijk om van elke numeric_type te converteren naar andere numeric_type met behulp van een cast-expressie (§12.9.7).
De expliciete numerieke conversies verliezen mogelijk informatie of veroorzaken mogelijk uitzonderingen. Een expliciete numerieke conversie wordt als volgt verwerkt:
- Voor een conversie van een integraal type naar een ander integraal type is de verwerking afhankelijk van de context van de overloopcontrole (§12.8.20) waarin de conversie plaatsvindt:
- In een
checked
context slaagt de conversie als de waarde van de bronoperand binnen het bereik van het doeltype valt, maar eenSystem.OverflowException
als de waarde van de bronoperand buiten het bereik van het doeltype valt. - In een
unchecked
context slaagt de conversie altijd en gaat het als volgt.- Als het brontype groter is dan het doeltype, wordt de bronwaarde afgekapt door de 'extra' belangrijkste bits te verwijderen. Het resultaat wordt vervolgens behandeld als een waarde van het doeltype.
- Als het brontype dezelfde grootte heeft als het doeltype, wordt de bronwaarde behandeld als een waarde van het doeltype
- In een
- Voor een conversie van
decimal
een integraal type wordt de bronwaarde afgerond op nul naar de dichtstbijzijnde integrale waarde en wordt deze integrale waarde het resultaat van de conversie. Als de resulterende integrale waarde buiten het bereik van het doeltype valt, wordt er eenSystem.OverflowException
gegenereerd. - Voor een conversie van
float
ofdouble
naar een integraal type is de verwerking afhankelijk van de context van overloopcontrole (§12.8.20) waarin de conversie plaatsvindt:- In een gecontroleerde context gaat de conversie als volgt:
- Als de waarde van de operand NaN of oneindig is, wordt er een
System.OverflowException
gegenereerd. - Anders wordt de bronoperand naar nul afgerond op de dichtstbijzijnde integrale waarde. Als deze integrale waarde binnen het bereik van het doeltype valt, is deze waarde het resultaat van de conversie.
- Anders wordt er een
System.OverflowException
gegooid.
- Als de waarde van de operand NaN of oneindig is, wordt er een
- In een niet-gecontroleerd context slaagt de conversie altijd en gaat het als volgt.
- Als de waarde van de operand NaN of oneindig is, is het resultaat van de conversie een niet-opgegeven waarde van het doeltype.
- Anders wordt de bronoperand naar nul afgerond op de dichtstbijzijnde integrale waarde. Als deze integrale waarde binnen het bereik van het doeltype valt, is deze waarde het resultaat van de conversie.
- Anders is het resultaat van de conversie een niet-opgegeven waarde van het doeltype.
- In een gecontroleerde context gaat de conversie als volgt:
- Voor een conversie van
double
naarfloat
, wordt dedouble
waarde afgerond op de dichtstbijzijndefloat
waarde. Als dedouble
waarde te klein is om als eenfloat
weer te geven, wordt het resultaat nul met hetzelfde teken als de waarde. Als de grootte van dedouble
waarde te groot is om als eenfloat
weer te geven, wordt het resultaat oneindig met hetzelfde teken als de waarde. Als dedouble
waarde NaN is, is het resultaat ook NaN. - Voor een conversie van
float
ofdouble
naardecimal
, wordt de bronwaarde indien nodig geconverteerd naardecimal
weergave en afgerond op het dichtstbijzijnde getal (§8.3.8).- Als de bronwaarde te klein is om als een
decimal
weer te geven, wordt het resultaat nul, waarbij het teken van de oorspronkelijke waarde behouden blijft alsdecimal
u ondertekende nulwaarden ondersteunt. - Als de grootte van de bronwaarde te groot is om weer te geven als een
decimal
, of als die waarde oneindig is, behoudt het resultaat het teken van de oorspronkelijke waarde, als de decimale weergave infinities ondersteunt; anders wordt er een System.OverflowException gegenereerd. - Als de bronwaarde NaN is, is het resultaat NaN als de decimale weergave NaN ondersteunt; anders wordt er een System.OverflowException gegenereerd.
- Als de bronwaarde te klein is om als een
- Voor een conversie van
decimal
naar offloat
double
wordt dedecimal
waarde afgerond op het dichtstbijzijnde ofdouble
de dichtstbijzijndefloat
waarde. Als de grootte van de bronwaarde te groot is om weer te geven in het doeltype of als die waarde oneindig is, behoudt het resultaat oneindigheid het teken van de oorspronkelijke waarde. Als de bronwaarde NaN is, is het resultaat NaN. Hoewel deze conversie precisie kan verliezen, wordt er nooit een uitzondering gegenereerd.
Opmerking: het type is niet vereist om infinities of NaN-waarden te ondersteunen, maar kan dit wel doen. Het
decimal
bereik is mogelijk kleiner dan het bereikfloat
endouble
, maar is niet gegarandeerd. Voordecimal
representaties zonder infiniteiten of NaN-waarden, en met een kleiner bereik danfloat
, is het resultaat van een conversie vandecimal
of naar offloat
double
nooit oneindig of NaN. eindnotitie
10.3.3 Expliciete opsommingsconversies
De expliciete opsommingsconversies zijn:
- Van
sbyte
,byte
,short
,ushort
, ,int
,uint
,long
ulong
char
,float
, ofdouble
decimal
naar een enum_type. - Van elke enum_type tot , , , ,
sbyte
byte
, ,short
, , ,ushort
int
uint
long
of .ulong
char
float
double
decimal
- Van enum_type tot andere enum_type.
Een expliciete opsommingsconversie tussen twee typen wordt verwerkt door alle deelnemende enum_type als het onderliggende type van die enum_type te behandelen en vervolgens een impliciete of expliciete numerieke conversie tussen de resulterende typen uit te voeren.
Voorbeeld: Uitgaande van een
E
int
met en het onderliggende type , wordt een conversie vanE
naarbyte
verwerkt als een expliciete numerieke conversie (§10.3.2E
§10.2.3) vanbyte
naarint
. eindvoorbeeld
10.3.4 Expliciete null-conversies
De expliciete null-conversies zijn de conversies die nullable zijn (§10.6.1) die zijn afgeleid van expliciete en impliciete vooraf gedefinieerde conversies.
10.3.5 Expliciete verwijzingsconversies
De expliciete verwijzingsconversies zijn:
- Van object naar andere reference_type.
- Van elke class_type
S
tot elke class_typeT
, opgegevenS
is een basisklasse vanT
. - Van elke
S
tot eenT
,S
wordt niet verzegeld enS
geleverd wordt niet geïmplementeerdT
. - Van elke
S
tot eenT
, die wordt geleverd,T
wordt niet verzegeld of geleverdT
implementeertS
. - Van elke interface_type
S
tot een interface_typeT
,S
die niet is afgeleid vanT
. - Van een array_type
S
met een elementtypeSᵢ
tot een array_typeT
met een elementtypeTᵢ
, mits alle volgende waar zijn:-
S
enT
verschilt alleen in elementtype. Met andere woorden,S
enT
hebben hetzelfde aantal dimensies. - Er bestaat een expliciete verwijzingsconversie van
Sᵢ
naarTᵢ
.
-
- Van
System.Array
en de interfaces die worden geïmplementeerd, op elke array_type. - Van ééndimensionale array_type tot , en de basisinterfaces ervan, mits er een identiteitsconversie of expliciete verwijzingsconversie van
S[]
naarSystem.Collections.Generic.IList<T>
.System.Collections.Generic.IReadOnlyList<T>
S
T
- Van
System.Collections.Generic.IList<S>
,System.Collections.Generic.IReadOnlyList<S>
en hun basisinterfaces naar een enkeldimensionaal matrixtypeT[]
, mits er een identiteitsconversie of expliciete verwijzingsconversie vanS
naar T is. - Van
System.Delegate
en de interfaces die worden geïmplementeerd in elke delegate_type. - Van een verwijzingstype naar een verwijzingstype
S
T
als het een expliciete verwijzingsconversie vanS
een verwijzingstype naar een verwijzingstypeT₀
heeft enT₀
er een identiteitsconversie vanT₀
naarT
. - Van een verwijzingstype
S
naar een interface of gedelegeerd typeT
als er een expliciete verwijzingsconversie is vanS
een interface of gemachtigde typeT₀
enT₀
een variantie-converteerbaar naar ofT
variantie-converteerbaarT
is naarT₀
§18.2.3.3. - Van
D<S₁...Sᵥ>
waarD<T₁...Tᵥ>
D<X₁...Xᵥ>
een algemeen gemachtigde type is,D<S₁...Sᵥ>
is niet compatibel met of identiekD<T₁...Tᵥ>
aan, en voor elk type parameterXᵢ
vanD
de volgende bewaring:- Als
Xᵢ
is invariant,Sᵢ
dan is identiek aanTᵢ
. - Als
Xᵢ
covariant is, is er een identiteitsconversie, impliciete verwijzingsconversie of expliciete verwijzingsconversie vanSᵢ
naarTᵢ
. - Als
Xᵢ
dit contravariant is,Sᵢ
zijn zeTᵢ
identiek of beide verwijzingstypen.
- Als
- Expliciete conversies met typeparameters die bekend zijn als referentietypen. Zie §10.3.8 voor meer informatie over expliciete conversies met typeparameters.
De expliciete verwijzingsconversies zijn die conversies tussen reference_types waarvoor runtimecontroles zijn vereist om ervoor te zorgen dat ze correct zijn.
De waarde van de bronoperand moet null
een expliciete verwijzingsconversie zijn, of het type object waarnaar wordt verwezen door de bronoperand moet een type zijn dat kan worden geconverteerd naar het doeltype door een impliciete verwijzingsconversie (§10.2.8). Als een expliciete verwijzingsconversie mislukt, wordt er een System.InvalidCastException
gegenereerd.
Opmerking: verwijzingsconversies, impliciet of expliciet, wijzigen nooit de waarde van de verwijzing zelf (§8.2.1), alleen het type. Het type of de waarde van het object waarnaar wordt verwezen, wordt ook niet gewijzigd. eindnotitie
10.3.6 Expliciete tuple-conversies
Een expliciete conversie bestaat van een tuple-expressie E
naar een tupletype T
als E
dezelfde arity heeft als T
en een impliciete of expliciete conversie bestaat van elk element in E
het bijbehorende elementtype in T
. De conversie wordt uitgevoerd door een exemplaar van T
het bijbehorende System.ValueTuple<...>
type te maken en elk van de velden te initialiseren in volgorde van links naar rechts door de bijbehorende tuple-elementexpressie te evalueren, E
te converteren naar het bijbehorende elementtype van het gebruik van T
de expliciete conversie gevonden en het veld te initialiseren met het resultaat.
10.3.7 Conversies uitpakken
Met een conversie van postvak UIT kan een reference_type expliciet worden geconverteerd naar een value_type. De volgende conversies voor het opheffen van postvakken bestaan:
- Van het type
object
tot elke value_type. - Van het type
System.ValueType
tot elke value_type. - Van het type
System.Enum
tot elke enum_type. - Van elke interface_type naar een non_nullable_value_type waarmee de interface_type wordt geïmplementeerd.
- Van elke
I
naar een non_nullable_value_type waar een conversie van een interface_typeI₀
naar het non_nullable_value-type en een identiteitsconversie vanI
naarI₀
. - Van elke
I
naar een non_nullable_value_type waar de conversie van een interface_typeI₀
naar de non_nullable_value_type ongedaan wordt gesteld en ofwelI₀
variance_convertible is ofI
I
is variantie-converteerbaar naarI₀
(§18.2.3.3). - Van elke reference_type naar een willekeurige nullable_value_type waarbij de conversie van reference_type naar de onderliggende non_nullable_value_type van de nullable_value_type is uitgeschakeld.
- Van een typeparameter die niet bekend is als een waardetype voor elk type, zodat de conversie is toegestaan door §10.3.8.
Een uitbox-bewerking voor een non_nullable_value_type bestaat uit het eerst controleren of het objectexemplaar een waarde in het vak van de opgegeven non_nullable_value_type is en vervolgens de waarde uit het exemplaar kopieert.
Als u de vakken op een nullable_value_type opheffen, wordt de null-waarde van de nullable_value_type als de bronoperand is null
, of het verpakte resultaat van het uitpakken van het objectexemplaren op het onderliggende type van de nullable_value_type anders.
Opmerking: Verwijzend naar de imaginaire boksklasse die wordt beschreven in §10.2.9, bestaat een uitboxingconversie van een objectvak naar een value_type
S
bestaat uit het uitvoeren van de expressie((S_Boxing)box).value
. De verklaringenobject box = new S(); S s = (S)box;
conceptueel overeenkomen met
object box = new S_Boxing(new S()); S s = ((S_Boxing)box).value;
eindnotitie
De waarde van de bronoperand is een verwijzing naar een vakkenwaarde van die non_nullable_value_type voor een conversie van het postvak uit te schakelen naar een gegeven non_nullable_value_type die in runtime kan slagen. Als de bronoperand een null
gegooid wordtSystem.NullReferenceException
. Als de bronoperand een verwijzing naar een niet-compatibel object is, wordt er een System.InvalidCastException
gegenereerd.
De waarde van de bronoperand moet null zijn of een verwijzing naar een vakkenwaarde van de onderliggende non_nullable_value_type van de nullable_value_type voor een conversie van het postvak uitpakken naar een gegeven nullable_value_type. Als de bronoperand een verwijzing naar een niet-compatibel object is, wordt er een System.InvalidCastException
gegenereerd.
10.3.8 Expliciete conversies met typeparameters
Voor een T
die bekend staat als referentietype (§15.2.5), bestaan de volgende expliciete verwijzingsconversies (§10.3.5):
- Van de effectieve basisklasse
C
vanT
van en naarT
elke basisklasse vanC
naarT
. - Van elke interface_type tot
T
. - Van
T
naar een interface_typeI
opgegeven is er nog geen impliciete verwijzingsconversie vanT
naarI
. - Van een
U
totT
voorwaarde datT
afhankelijk isU
van (§15.2.5).Opmerking: Aangezien
T
het een verwijzingstype is, binnen het bereik vanT
, is het runtimetype van u altijd een verwijzingstype, zelfs alsU
dit niet bekend is als een verwijzingstype tijdens het compileren. eindnotitie
Voor een T
die niet bekend is als een referentietype (§15.2.5), worden de volgende conversies met betrekking T
tot het inpakken van conversies (§10.3.7) tijdens het compileren beschouwd. Als dit een waardetype is, T
wordt de conversie tijdens runtime uitgevoerd als een conversie voor het opheffen van postvakken. Als dit een verwijzingstype is, T
wordt de conversie uitgevoerd als expliciete verwijzingsconversie of identiteitsconversie.
- Van de effectieve basisklasse
C
vanT
van en naarT
elke basisklasse vanC
naarT
.Opmerking: C is een van de typen
System.Object
,System.ValueType
ofSystem.Enum
(andersT
zou het een verwijzingstype zijn). eindnotitie - Van elke interface_type tot
T
.
Voor een T
die niet bekend staat als referentietype (§15.2.5), bestaan de volgende expliciete conversies:
- Van
T
naar een interface_typeI
mits er nog geen impliciete conversie vanT
naarI
. Deze conversie bestaat uit een impliciete boksconversie (§10.2.9) vanT
naarobject
gevolgd door een expliciete verwijzingsconversie vanobject
naarI
. Als dit een waardetype is,T
wordt de conversie uitgevoerd als een boksconversie, gevolgd door een expliciete verwijzingsconversie. Als dit een verwijzingstype is,T
wordt de conversie uitgevoerd als een expliciete verwijzingsconversie. - Van een typeparameter
U
totT
opgegeven dieT
afhankelijkU
is van (§15.2.5).T
Als dit een waardetype is enU
een verwijzingstype is, wordt de conversie uitgevoerd als een conversie voor het uitpakken van de vakken. Tijdens runtime, als beideT
enU
waardetypen zijn,T
enU
noodzakelijkerwijs hetzelfde type zijn en er geen conversie wordt uitgevoerd. Als dit een verwijzingstype is,T
is ditU
noodzakelijkerwijs ook een verwijzingstype en wordt de conversie uitgevoerd als een expliciete verwijzingsconversie of identiteitsconversie.
In alle gevallen zorgen de regels ervoor dat een conversie wordt uitgevoerd als een conversie voor het opheffen van postvakken als en alleen als de conversie tijdens runtime van een verwijzingstype naar een waardetype is.
De bovenstaande regels staan geen directe expliciete conversie toe van een niet-gekoppelde typeparameter naar een niet-interfacetype, wat mogelijk verrassend is. De reden voor deze regel is om verwarring te voorkomen en de semantiek van dergelijke conversies duidelijk te maken.
Voorbeeld: Bekijk de volgende declaratie:
class X<T> { public static long F(T t) { return (long)t; // Error } }
Als de directe expliciete conversie van
t
naarlong
is toegestaan, kan men gemakkelijk verwachten dat datX<int>.F(7)
zou retourneren7L
. Dit zou echter niet zo zijn, omdat de standaard numerieke conversies alleen worden overwogen wanneer de typen numeriek zijn op bindingstijd. Om de semantiek duidelijk te maken, moet het bovenstaande voorbeeld in plaats daarvan worden geschreven:class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }
Deze code wordt nu gecompileerd, maar het uitvoeren
X<int>.F(7)
zou vervolgens een uitzondering genereren tijdens runtime, omdat een boxedint
niet rechtstreeks kan worden geconverteerd naar eenlong
.eindvoorbeeld
10.3.9 Door de gebruiker gedefinieerde expliciete conversies
Een door de gebruiker gedefinieerde expliciete conversie bestaat uit een optionele standaard expliciete conversie, gevolgd door de uitvoering van een door de gebruiker gedefinieerde impliciete of expliciete conversieoperator, gevolgd door een andere optionele standaard expliciete conversie. De exacte regels voor het evalueren van door de gebruiker gedefinieerde expliciete conversies worden beschreven in §10.5.5.
10.4 Standaardconversies
10.4.1 Algemeen
De standaardconversies zijn die vooraf gedefinieerde conversies die kunnen optreden als onderdeel van een door de gebruiker gedefinieerde conversie.
10.4.2 Standaard impliciete conversies
De volgende impliciete conversies worden geclassificeerd als standaard impliciete conversies:
- Identiteitsconversies (§10.2.2)
- Impliciete numerieke conversies (§10.2.3)
- Impliciete null-conversies (§10.2.6)
- Null-letterlijke conversies (§10.2.7)
- Impliciete verwijzingsconversies (§10.2.8)
- Boksen conversies (§10.2.9)
- Impliciete conversie van constante expressies (§10.2.11)
- Impliciete conversies met typeparameters (§10.2.12)
De standaard impliciete conversies sluiten specifiek door de gebruiker gedefinieerde impliciete conversies uit.
10.4.3 Standaard expliciete conversies
De expliciete standaardconversies zijn alle standaard impliciete conversies plus de subset van de expliciete conversies waarvoor een tegenovergestelde impliciete standaardconversie bestaat.
Opmerking: Met andere woorden, als er een standaard impliciete conversie bestaat van een type
A
naar een typeB
, bestaat er een standaard expliciete conversie van typeA
naar typeB
en van type naar typeB
A
. eindnotitie
10.5 Door de gebruiker gedefinieerde conversies
10.5.1 Algemeen
Met C# kunnen de vooraf gedefinieerde impliciete en expliciete conversies worden uitgebreid met door de gebruiker gedefinieerde conversies. Door de gebruiker gedefinieerde conversies worden geïntroduceerd door conversieoperators (§15.10.4) in klasse- en structtypen te declareren.
10.5.2 Toegestane door de gebruiker gedefinieerde conversies
Met C# kunnen alleen bepaalde door de gebruiker gedefinieerde conversies worden gedeclareerd. Het is met name niet mogelijk om een reeds bestaande impliciete of expliciete conversie opnieuw te definiëren.
Voor een bepaald brontype S
en doeltype T
, als S
of T
null-waardetypen zijn, kunt u de onderliggende typen toestaan S₀
en T₀
raadplegen, anders S₀
en T₀
zijn ze gelijk aan S
en T
respectievelijk. Een klasse of struct mag alleen een conversie van een brontype S
naar een doeltype T
declareren als alle volgende waar zijn:
-
S₀
enT₀
zijn verschillende typen. - Of
S₀
is het klasse-T₀
of structtype waarin de operatordeclaratie plaatsvindt. -
S₀
NochT₀
een interface_type. - Met uitzondering van door de gebruiker gedefinieerde conversies bestaat er geen conversie van
S
naarT
of vanT
.S
De beperkingen die van toepassing zijn op door de gebruiker gedefinieerde conversies worden opgegeven in §15.10.4.
10.5.3 Evaluatie van door de gebruiker gedefinieerde conversies
Een door de gebruiker gedefinieerde conversie converteert een bronexpressie, die mogelijk een brontype heeft, naar een ander type, het doeltype genoemd. Evaluatie van een door de gebruiker gedefinieerde conversiecentra voor het vinden van de meest specifieke door de gebruiker gedefinieerde conversieoperator voor de bronexpressie en het doeltype. Deze bepaling wordt onderverdeeld in verschillende stappen:
- De set klassen en structs zoeken waaruit door de gebruiker gedefinieerde conversieoperators worden overwogen. Deze set bestaat uit het brontype en de basisklassen, als het brontype bestaat, samen met het doeltype en de bijbehorende basisklassen. Voor dit doel wordt ervan uitgegaan dat alleen klassen en structs door de gebruiker gedefinieerde operators kunnen declareren en dat niet-klassetypen geen basisklassen hebben. Als het bron- of doeltype ook een nullable-value-type is, wordt het onderliggende type in plaats daarvan gebruikt.
- Vanuit die set typen bepalen welke door de gebruiker gedefinieerde en lifted conversieoperators van toepassing zijn. Voor een conversieoperator die van toepassing is, moet het mogelijk zijn om een standaardconversie (§10.4) uit te voeren van de bronexpressie naar het operandtype van de operator, en moet het mogelijk zijn om een standaardconversie uit te voeren van het resultaattype van de operator naar het doeltype.
- Bepaal uit de set van toepasselijke door de gebruiker gedefinieerde operators welke operator ondubbelzinnig de meest specifieke operator is. In het algemeen is de meest specifieke operator de operator waarvan het operandtype het dichtst bij de bronexpressie ligt en waarvan het resultaattype het dichtst bij het doeltype ligt. Door de gebruiker gedefinieerde conversieoperators hebben de voorkeur boven lifted conversieoperators. De exacte regels voor het tot stand brengen van de meest specifieke door de gebruiker gedefinieerde conversieoperator worden gedefinieerd in de volgende subclauses.
Zodra een meest specifieke door de gebruiker gedefinieerde conversieoperator is geïdentificeerd, bestaat de daadwerkelijke uitvoering van de door de gebruiker gedefinieerde conversie uit maximaal drie stappen:
- Voer eerst, indien nodig, een standaardconversie van de bronexpressie uit naar het operandtype van de door de gebruiker gedefinieerde of lifted conversieoperator.
- Roep vervolgens de door de gebruiker gedefinieerde of lifted conversieoperator aan om de conversie uit te voeren.
- Ten slotte voert u, indien nodig, een standaardconversie uit van het resultaattype van de door de gebruiker gedefinieerde conversieoperator naar het doeltype.
Evaluatie van een door de gebruiker gedefinieerde conversie omvat nooit meer dan één door de gebruiker gedefinieerde of lifted conversieoperator. Met andere woorden, een conversie van type S
naar type T
voert nooit eerst een door de gebruiker gedefinieerde conversie van S
naar X
en vervolgens een door de gebruiker gedefinieerde conversie van X
naar T
.
- Exacte definities van evaluatie van door de gebruiker gedefinieerde impliciete of expliciete conversies worden gegeven in de volgende subclauses. De definities maken gebruik van de volgende termen:
- Als een standaard impliciete conversie (§10.4.2) bestaat van een type
A
naar een typeB
, en als nochA
B
interface_types
zijn , danA
wordt gezegd te omvattenB
, enB
wordt gezegd te omvatten .A
- Als een standaard impliciete conversie (§10.4.2) bestaat van een expressie
E
tot een typeB
, en als nochB
het typeE
(indien het een heeft)s
zijn, danE
wordt gezegd dat deze omvat door, en wordt gezegd teB
B
E
. - Het meest omvattende type in een set typen is het ene type dat alle andere typen in de set omvat. Als geen enkel type alle andere typen omvat, heeft de set geen meest omvattend type. In intuïtievere termen is het meest omvattende type het 'grootste' type in de set: het ene type waarnaar elk van de andere typen impliciet kan worden geconverteerd.
- Het meest omvattende type in een set typen is het ene type dat wordt omvat door alle andere typen in de set. Als er geen enkel type is opgenomen in alle andere typen, heeft de set geen meest omvattend type. In intuïtievere termen is het meest omvattende type het kleinste type in de set: het ene type dat impliciet kan worden geconverteerd naar elk van de andere typen.
10.5.4 Door de gebruiker gedefinieerde impliciete conversies
Een door de gebruiker gedefinieerde impliciete conversie van een expressie E
naar een type T
wordt als volgt verwerkt:
Bepaal de typen
S
enS₀
T₀
.- Als
E
u een type hebt, laatS
u dat type zijn. - Als
S
ofT
null-waardetypen zijn, laatSᵢ
en zijn ze de onderliggende typen, laat zeTᵢ
anders toeSᵢ
enTᵢ
S
T
, respectievelijk. - Als
Sᵢ
ofTᵢ
typeparameters zijn, laatS₀
en zijn ze hun effectieve basisklassen, laat zeT₀
anders toeS₀
enT₀
Sₓ
Tᵢ
, respectievelijk.
- Als
Zoek de set typen,
D
van waaruit door de gebruiker gedefinieerde conversieoperators worden overwogen. Deze set bestaat uitS₀
(indienS₀
aanwezig en is een klasse of struct), de basisklassenS₀
van (indienS₀
aanwezig en is een klasse) enT₀
(alsT₀
het een klasse of struct is). Er wordt alleen een type aan de setD
toegevoegd als er geen identiteitsconversie naar een ander type bestaat dat al in de set is opgenomen.Zoek de set toepasselijke door de gebruiker gedefinieerde en lifted conversieoperators.
U
Deze set bestaat uit de door de gebruiker gedefinieerde en opgeheven impliciete conversieoperators die zijn gedeclareerd door de klassen of structs inD
die worden omgezet van een type dat omvatE
tot een type dat wordt omvat doorT
. AlsU
deze leeg is, is de conversie niet gedefinieerd en treedt er een compileertijdfout op.- Indien
S
aanwezig en een van de operators inU
converteren vanS
, danSₓ
isS
. - Anders is dit
Sₓ
het meest omvattende type in de gecombineerde set brontypen van de operators inU
. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
- Indien
Zoek het meest specifieke doeltype,
Tₓ
van de operators inU
:- Als een van de operators die
U
worden geconverteerd naarT
, danTₓ
isT
. - Anders is het
Tₓ
meest omvattende type in de gecombineerde set doeltypen van de operators inU
. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
- Als een van de operators die
Zoek de meest specifieke conversieoperator:
- Als
U
er precies één door de gebruiker gedefinieerde conversieoperator is waaruit wordt geconverteerdSₓ
Tₓ
, is dit de meest specifieke conversieoperator. -
U
Als dit niet precies één lifted conversieoperator bevat die vanSₓ
Tₓ
waaruit wordt geconverteerd, is dit de meest specifieke conversieoperator. - Anders is de conversie dubbelzinnig en treedt er een compilatietijdfout op.
- Als
Pas ten slotte de conversie toe:
- Als E het type
Sₓ
nog niet heeft, wordt er een standaard impliciete conversie vanE
naarSₓ
uitgevoerd. - De meest specifieke conversieoperator wordt aangeroepen om van te converteren
Sₓ
naarTₓ
. - Als
Tₓ
dat nietT
het is, wordt een standaard impliciete conversie vanTₓ
naarT
uitgevoerd.
- Als E het type
Een door de gebruiker gedefinieerde impliciete conversie van een type S
naar een type T
bestaat als een door de gebruiker gedefinieerde impliciete conversie bestaat van een variabele van het type S
naar T
.
10.5.5 Door de gebruiker gedefinieerde expliciete conversies
Een door de gebruiker gedefinieerde expliciete conversie van een expressie E
naar een type T
wordt als volgt verwerkt:
- Bepaal de typen
S
enS₀
T₀
.- Als
E
u een type hebt, laatS
u dat type zijn. - Als
S
ofT
null-waardetypen zijn, laatSᵢ
en zijn ze de onderliggende typen, laat zeTᵢ
anders toeSᵢ
enTᵢ
S
T
, respectievelijk. - Als
Sᵢ
ofTᵢ
typeparameters zijn, laatS₀
en zijn ze hun effectieve basisklassen, laat zeT₀
anders toeS₀
enT₀
Sᵢ
Tᵢ
, respectievelijk.
- Als
- Zoek de set typen,
D
van waaruit door de gebruiker gedefinieerde conversieoperators worden overwogen. Deze set bestaat uitS₀
(indienS₀
aanwezig en is een klasse of struct), de basisklassenS₀
van (indienS₀
aanwezig en is een klasse),T₀
(alsT₀
dit een klasse of struct is) en de basisklassen vanT₀
(alsT₀
dit een klasse is).A
het type wordt alleen toegevoegd aan de setD
als een identiteitsconversie naar een ander type dat al in de set is opgenomen, niet bestaat. - Zoek de set toepasselijke door de gebruiker gedefinieerde en lifted conversieoperators.
U
Deze set bestaat uit de door de gebruiker gedefinieerde en opgeheven impliciete of expliciete conversieoperators die zijn gedeclareerd door de klassen of structs inD
die conversie van een type dat omvatE
of omvat doorS
(indien aanwezig) naar een type dat omvat of omvat doorT
. AlsU
deze leeg is, is de conversie niet gedefinieerd en treedt er een compileertijdfout op. - Zoek het meest specifieke brontype,
Sₓ
van de operators inU
:- Als S bestaat en een van de operators die worden
U
geconverteerd vanS
, danSₓ
isS
. - Als een van de operators die
U
worden geconverteerd van typen die omvattenE
, is ditSₓ
anders het meest omvattende type in de gecombineerde set brontypen van deze operators. Als er geen meest omvattend type kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op. - Anders is het
Sₓ
meest omvattende type in de gecombineerde set brontypen van de operators inU
. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
- Als S bestaat en een van de operators die worden
- Zoek het meest specifieke doeltype,
Tₓ
van de operators inU
:- Als een van de operators die
U
worden geconverteerd naarT
, danTₓ
isT
. - Als een van de operators die
U
worden geconverteerd naar typen die zijn opgenomen inT
, is ditTₓ
anders het meest omvattende type in de gecombineerde set doeltypen van deze operators. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op. -
Tₓ
Anders is het meest omvattende type in de gecombineerde set doeltypen van de operators inU
. Als er geen meest omvattend type kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
- Als een van de operators die
- Zoek de meest specifieke conversieoperator:
- Als U precies één door de gebruiker gedefinieerde conversieoperator bevat die van
Sₓ
Tₓ
waaruit wordt geconverteerd, is dit de meest specifieke conversieoperator. -
U
Als dit niet precies één lifted conversieoperator bevat die vanSₓ
Tₓ
waaruit wordt geconverteerd, is dit de meest specifieke conversieoperator. - Anders is de conversie dubbelzinnig en treedt er een compilatietijdfout op.
- Als U precies één door de gebruiker gedefinieerde conversieoperator bevat die van
- Pas ten slotte de conversie toe:
- Als
E
dit nog niet het typeSₓ
heeft, wordt een standaard expliciete conversie van E naarSₓ
uitgevoerd. - De meest specifieke door de gebruiker gedefinieerde conversieoperator wordt aangeroepen om te converteren van
Sₓ
naarTₓ
. - Als
Tₓ
dat nietT
zo is, wordt een standaard expliciete conversie vanTₓ
naarT
uitgevoerd.
- Als
Een door de gebruiker gedefinieerde expliciete conversie van een type S
naar een type T
bestaat als een door de gebruiker gedefinieerde expliciete conversie bestaat van een variabele van het type S
naar T
.
10.6 Conversies met null-typen
10.6.1 Nullable Conversies
Met null-conversies kunnen vooraf gedefinieerde conversies die worden uitgevoerd op niet-nullable waardetypen, ook worden gebruikt met null-formulieren van deze typen. Voor elk van de vooraf gedefinieerde impliciete of expliciete conversies die worden geconverteerd van een niet-null-waardetype S
naar een niet-null-waardetype T
(§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 en §10.3.3), bestaan de volgende null-conversies:
- Een impliciete of expliciete conversie van
S?
naarT?
- Een impliciete of expliciete conversie van
S
naarT?
- Een expliciete conversie van
S?
naarT
.
Een null-conversie wordt zelf geclassificeerd als een impliciete of expliciete conversie.
Bepaalde null-conversies worden geclassificeerd als standaardconversies en kunnen worden uitgevoerd als onderdeel van een door de gebruiker gedefinieerde conversie. Met name worden alle impliciete null-conversies geclassificeerd als standaard impliciete conversies (§10.4.2) en deze expliciete null-conversies die voldoen aan de vereisten van §10.4.3 worden geclassificeerd als standaard expliciete conversies.
Evaluatie van een null-conversie op basis van een onderliggende conversie van S
naar gaat T
als volgt:
- Als de conversie die null kan worden uitgevoerd, van
S?
naarT?
:- Als de bronwaarde null is (
HasValue
eigenschap isfalse
), is het resultaat de null-waarde van het typeT?
. - Anders wordt de conversie geëvalueerd als uitpakken van
S?
naarS
, gevolgd door de onderliggende conversie vanS
naarT
, gevolgd door een terugloop vanT
naarT?
.
- Als de bronwaarde null is (
- Als de null-conversie van
S
naar isT?
, wordt de conversie geëvalueerd als de onderliggende conversie vanS
naarT
gevolgd door een terugloop vanT
naarT?
. - Als de null-conversie van
S?
naar isT
, wordt de conversie geëvalueerd als uitpakken vanS?
naarS
gevolgd door de onderliggende conversie vanS
naarT
.
10.6.2 Lifted conversies
Gezien een door de gebruiker gedefinieerde conversieoperator die wordt geconverteerd van een niet-nullable waardetype S
naar een niet-nullable waardetypeT
, bestaat er een lifted conversieoperator die wordt geconverteerd van S?
naar T?
. Deze opgetilde conversieoperator voert een uitgepakt van S?
naar S
gevolgd door de door de gebruiker gedefinieerde conversie van S
naar T
gevolgd door een terugloop van T
naar T?
, behalve dat een null-waarde die S?
rechtstreeks wordt geconverteerd naar een null-waarde .T?
Een lifted conversion operator heeft dezelfde impliciete of expliciete classificatie als de onderliggende door de gebruiker gedefinieerde conversieoperator.
10.7 Anonieme functieconversies
10.7.1 Algemeen
Een anonymous_method_expression of lambda_expression wordt geclassificeerd als anonieme functie (§12.19). De expressie heeft geen type, maar kan impliciet worden geconverteerd naar een compatibel gemachtigdentype. Sommige lambda-expressies kunnen ook impliciet worden geconverteerd naar een compatibel type expressiestructuur.
Een anonieme functie F
is met name compatibel met een opgegeven gemachtigde:D
- Als
F
dit een anonymous_function_signature bevat,D
F
moet u hetzelfde aantal parameters hebben. - Als
F
dit geen anonymous_function_signature bevat,D
kan het zijn dat er nul of meer parameters van een willekeurig type zijn, zolang er geen parameter vanD
een uitvoerparameter is. - Als
F
er een expliciet getypte parameterlijst is, heeft elke parameterD
dezelfde modifiers als de bijbehorende parameter inF
en bestaat er een identiteitsconversie tussen de bijbehorende parameter inF
. - Als
F
er een impliciet getypte parameterlijst is,D
heeft u geen verwijzings- of uitvoerparameters. - Als de hoofdtekst
F
een expressie is enD
ongeldig retourtypeF
asynchroon is enD
een«TaskType»
retourtype (§15.15.15.1) heeft, is deF
D
hoofdtekstF
een geldige expressie (w.r.t §12) die is toegestaan als een statement_expression (§13.7). - Als de hoofdtekst
F
van een blok is en eenD
ongeldig retourtype heeft ofF
asynchroon is enD
een«TaskType»
retourtype heeft, krijgt elke parameterF
het type van de overeenkomstige parameter inD
, dan is de hoofdtekstF
van een geldig blok (w.r.t §13.3) waarin geenreturn
instructie een expressie aangeeft. - Als de hoofdtekst
F
van een expressie is enF
is enD
een niet-retourtypevoid
T
heeft,F
asynchroon is enD
een«TaskType»<T>
retourtype (§15.15.15.1) heeft, is deF
D
hoofdtekstF
van een geldige expressie (w.r.t §12) die impliciet wordt geconverteerd naar .T
- Als de hoofdtekst
F
van een blok is en niet-asynchroonF
is enD
een niet-ongeldig retourtypeT
heeft,F
asynchroon is enD
een«TaskType»<T>
retourtype heeft, krijgt elke parameterF
het type van de bijbehorende parameter inD
, dan is de hoofdtekstF
een geldig instructieblok (w.r.t §13.3) met een niet-bereikbaar eindpunt waarin elke retourinstructie een expressie aangeeft die impliciet converteerbaar is naarT
.
Voorbeeld: In de volgende voorbeelden ziet u de volgende regels:
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"; };
eindvoorbeeld
Voorbeeld: De volgende voorbeelden gebruiken een algemeen gemachtigdentype
Func<A,R>
dat een functie vertegenwoordigt die een argument van het typeA
gebruikt en een waarde van het typeR
retourneert:delegate R Func<A,R>(A arg);
In de opdrachten
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; // Ok
de parameter en retourtypen van elke anonieme functie worden bepaald op basis van het type variabele waaraan de anonieme functie is toegewezen.
De eerste toewijzing converteert de anonieme functie naar het type gemachtigde
Func<int,int>
omdat, wanneerx
het typeint
is opgegeven,x + 1
een geldige expressie is die impliciet kan worden omgezet in typeint
.Op dezelfde manier converteert de tweede opdracht de anonieme functie naar het gemachtigde type Func<int, dubbel> omdat het resultaat van
x + 1
(van het typeint
) impliciet converteert naar typedouble
.De derde toewijzing is echter een compilatiefout omdat, wanneer
x
het opgegeven typedouble
is, het resultaat vanx + 1
(van het typedouble
) niet impliciet converteerbaar is naar typeint
.De vierde toewijzing converteert de anonieme asynchrone functie naar het gemachtigde type
Func<int, Task<int>>
omdat het resultaat vanx + 1
(van het typeint
) impliciet wordt omgezet in het effectieve retourtypeint
van de asynchrone lambda, dat een retourtypeTask<int>
heeft.eindvoorbeeld
Een lambda-expressie F
is compatibel met een expressiestructuurtype Expression<D>
als F
deze compatibel is met het type D
gemachtigde. Dit geldt niet voor anonieme methoden, alleen lambda-expressies.
Anonieme functies kunnen invloed hebben op overbelastingsresolutie en deelnemen aan typedeductie. Zie §12.6 voor meer informatie.
10.7.2 Evaluatie van anonieme functieconversies naar gedelegeerde typen
De conversie van een anonieme functie naar een gemachtigdentype produceert een gemachtigde instantie die verwijst naar de anonieme functie en de (mogelijk lege) set vastgelegde buitenste variabelen die actief zijn op het moment van de evaluatie. Wanneer de gemachtigde wordt aangeroepen, wordt de hoofdtekst van de anonieme functie uitgevoerd. De code in de hoofdtekst wordt uitgevoerd met behulp van de set vastgelegde buitenste variabelen waarnaar wordt verwezen door de gemachtigde. Een delegate_creation_expression (§12.8.17.6) kan worden gebruikt als een alternatieve syntaxis voor het converteren van een anonieme methode naar een gemachtigde.
De aanroeplijst van een gemachtigde die is geproduceerd uit een anonieme functie bevat één vermelding. De exacte doelobject- en doelmethode van de gemachtigde zijn niet opgegeven. In het bijzonder is het niet opgegeven of het doelobject van de gemachtigde is null
, de this
waarde van het insluitende functielid of een ander object.
Conversies van semantisch identieke anonieme functies met dezelfde (mogelijk lege) set vastgelegde instanties van buitenvariabelen zijn toegestaan (maar niet vereist) om dezelfde gemachtigde instantie te retourneren. De term semantisch identiek wordt hier gebruikt om te betekenen dat de uitvoering van de anonieme functies in alle gevallen dezelfde effecten zal opleveren op basis van dezelfde argumenten. Met deze regel kan code, zoals het volgende, worden geoptimaliseerd.
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));
...
}
}
Aangezien de twee anonieme functiedelegen dezelfde (lege) set vastgelegde buitenste variabelen hebben en omdat de anonieme functies semantisch identiek zijn, mag een compiler de gedelegeerden naar dezelfde doelmethode laten verwijzen. Inderdaad, een compiler mag hetzelfde delegate-object retourneren van beide anonieme functie-expressies.
10.7.3 Evaluatie van lambda-expressieconversies naar expressiestructuurtypen
De conversie van een lambda-expressie naar een expressiestructuurtype produceert een expressiestructuur (§8.6). De evaluatie van de lambda-expressieconversie produceert een objectstructuur die de structuur van de lambda-expressie zelf vertegenwoordigt.
Niet elke lambda-expressie kan worden geconverteerd naar expressiestructuurtypen. De conversie naar een compatibel type gemachtigde bestaat altijd, maar kan mislukken tijdens het compileren om door de implementatie gedefinieerde redenen.
Opmerking: Veelvoorkomende redenen waarom een lambda-expressie niet kan worden geconverteerd naar een expressiestructuurtype, zijn onder andere:
- Het heeft een bloktekst
- Het heeft de
async
wijzigingsfunctie- Deze bevat een toewijzingsoperator
- Deze bevat een uitvoer- of verwijzingsparameter
- Deze bevat een dynamisch gebonden expressie
eindnotitie
10.8 Groepsconversies
Er bestaat een impliciete conversie van een methodegroep (§12.2) naar een compatibel gemachtigdetype (§20.4). Als D
een gemachtigde is en E
een expressie is die is geclassificeerd als een methodegroep, is dan D
alleen compatibel met E
als en alleen als E
er ten minste één methode bevat die van toepassing is in de normale vorm (§12.6.4.2) op een lijst met argumenten (§12.6.2) met typen en modifiers die overeenkomen met de parametertypen en modifiers van D
, zoals beschreven in het volgende.
De compilatietijdtoepassing van de conversie van een methodegroep E
naar een gedelegeerde type D
wordt in het volgende beschreven.
- Er wordt één methode
M
geselecteerd die overeenkomt met een methode-aanroep (§12.8.10.2) van het formulierE(A)
, met de volgende wijzigingen:- De argumentenlijst
A
is een lijst met expressies, die elk zijn geclassificeerd als een variabele en met het type en de wijzigingsfunctie (in
,out
ofref
) van de bijbehorende parameter in het parameter_list vanD
, met uitzondering van parameters van het typedynamic
, waarbij de bijbehorende expressie het typeobject
heeft in plaats vandynamic
. - De kandidaatmethoden die worden beschouwd, zijn alleen methoden die van toepassing zijn in hun normale vorm en laten geen optionele parameters weg (§12.6.4.2). Kandidaatmethoden worden dus genegeerd als ze alleen van toepassing zijn in hun uitgevouwen vorm, of als een of meer van hun optionele parameters geen bijbehorende parameter hebben.
D
- De argumentenlijst
- Een conversie wordt beschouwd als het algoritme van §12.8.10.2
D
- Als de geselecteerde methode
M
een exemplaarmethode is, bepaalt de exemplaarexpressie die isE
gekoppeld aan het doelobject van de gemachtigde. - Als de geselecteerde methode een uitbreidingsmethode
M
is die wordt aangeduid met behulp van lidtoegang voor een exemplaarexpressie, bepaalt die instantie-expressie het doelobject van de gemachtigde. - Het resultaat van de conversie is een waarde van het type
D
, namelijk een gemachtigde die verwijst naar de geselecteerde methode en het doelobject.
Voorbeeld: Hieronder ziet u groepsconversies van methoden:
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 } }
De toewijzing om
d1
impliciet de methodegroepF
te converteren naar een waarde van het typeD1
.De toewijzing om te
d2
laten zien hoe het mogelijk is om een gemachtigde te maken voor een methode met minder afgeleide parametertypen (contravariant) en een meer afgeleid (covariant) retourtype.De toewijzing om te
d3
laten zien hoe er geen conversie bestaat als de methode niet van toepassing is.De toewijzing die laat
d4
zien hoe de methode van toepassing moet zijn in de normale vorm.De toewijzing om te
d5
laten zien hoe parameter- en retourtypen van de gemachtigde en methode alleen mogen verschillen voor referentietypen.eindvoorbeeld
Net als bij alle andere impliciete en expliciete conversies kan de cast-operator worden gebruikt om expliciet een bepaalde conversie uit te voeren.
Voorbeeld: Het voorbeeld
object obj = new EventHandler(myDialog.OkClick);
kan in plaats daarvan worden geschreven
object obj = (EventHandler)myDialog.OkClick;
eindvoorbeeld
Een methodegroepconversie kan verwijzen naar een algemene methode, hetzij door expliciet typeargumenten op te geven binnen E
of via typedeductie (§12.6.3). Als typedeductie wordt gebruikt, worden de parametertypen van de gemachtigde gebruikt als argumenttypen in het deductieproces. Het retourtype van de gemachtigde wordt niet gebruikt voor deductie. Of de typeargumenten worden opgegeven of afgeleid, ze maken deel uit van het conversieproces van de methodegroep; dit zijn de typeargumenten die worden gebruikt om de doelmethode aan te roepen wanneer de resulterende gemachtigde wordt aangeroepen.
Voorbeeld:
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 } }
eindvoorbeeld
Methodegroepen kunnen invloed hebben op overbelastingsresolutie en deelnemen aan typedeductie. Zie §12.6 voor meer informatie.
De runtime-evaluatie van een methodegroepconversie gaat als volgt:
- Als de methode die tijdens het compileren is geselecteerd, een exemplaarmethode is of een extensiemethode is die als instantiemethode wordt geopend, wordt het doelobject van de gemachtigde bepaald op basis van de instantie-expressie die is gekoppeld aan
E
:- De exemplaarexpressie wordt geëvalueerd. Als deze evaluatie een uitzondering veroorzaakt, worden er geen verdere stappen uitgevoerd.
- Als de exemplaarexpressie van een reference_type is, wordt de waarde die wordt berekend door de exemplaarexpressie het doelobject. Als de geselecteerde methode een exemplaarmethode is en het doelobject is
null
, wordt er eenSystem.NullReferenceException
gegenereerd en worden er geen verdere stappen uitgevoerd. - Als de exemplaarexpressie van een value_type is, wordt een boksbewerking (§10.2.9) uitgevoerd om de waarde te converteren naar een object en wordt dit object het doelobject.
- Anders maakt de geselecteerde methode deel uit van een statische methode-aanroep en is
null
het doelobject van de gemachtigde. - Een gemachtigde instantie van het type gemachtigde
D
wordt als volgt verkregen met een verwijzing naar de methode die tijdens het compileren is bepaald en een verwijzing naar het hierboven berekende doelobject:- De conversie is toegestaan (maar niet vereist) om een bestaand gemachtigde exemplaar te gebruiken dat deze verwijzingen al bevat.
- Als een bestaand exemplaar niet opnieuw is gebruikt, wordt er een nieuwe gemaakt (§20.5). Als er onvoldoende geheugen beschikbaar is om het nieuwe exemplaar toe te wijzen, wordt er een
System.OutOfMemoryException
gegenereerd. Anders wordt het exemplaar geïnitialiseerd met de opgegeven verwijzingen.
ECMA C# draft specification