Delen via


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 type long is bijvoorbeeld impliciet, zodat expressies van het type int impliciet als type longkunnen worden behandeld. De tegenovergestelde conversie, van type long naar type int, 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 en T, voor elk type T.
  • Tussen T en T? voor elk verwijzingstype T.
  • Tussen object en dynamic.
  • 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 t1en t2t3 hebben allemaal twee elementen: een int gevolgd door een string. Tuple-elementtypen kunnen zichzelf door tuples, zoals in t4, t5en t6. Er bestaat een identiteitsconversie tussen elk paar bijbehorende elementtypen, inclusief geneste tuples, waardoor er een identiteitsconversie bestaat tussen de typen tuples t4, t5en t6.

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 naar short, int, long, , , floatof doubledecimal.
  • Van byte naar short, ushort, , int, uint, , long, ulong, , float, , doubleof decimal.
  • Van short naar int, long, float, of doubledecimal.
  • Van ushort naar int, uint, long, , ulong, , float, of double.decimal
  • Van int naar long, float, of doubledecimal.
  • Van uint naar long, ulong, float, of doubledecimal.
  • Van long naar float, doubleof decimal.
  • Van ulong naar float, doubleof decimal.
  • Van char naar ushort, int, , uint, long, , ulong, , float, , doubleof decimal.
  • Van float in double.

Conversies vanint, uintlong of van en ulongfloat 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.FormattableStringSystem.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 en dynamic.
  • Van elke class_typeS tot een class_typeT, die S wordt verstrekt, is afgeleid van T.
  • Van elke class_typeS tot elke interface_typeT, geleverd S implementeert T.
  • Van elke interface_typeS tot een interface_typeT, die S wordt verstrekt, is afgeleid van T.
  • Van een array_typeS met een elementtype Sᵢ tot een array_typeT met een elementtype Tᵢ, mits alle volgende waar zijn:
    • S en T verschilt alleen in elementtype. Met andere woorden, S en T hebben hetzelfde aantal dimensies.
    • Er bestaat een impliciete verwijzingsconversie van Sᵢ naar Tᵢ.
  • Van een enkeldimensionaal matrixtype S[] naar System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>en de bijbehorende basisinterfaces, mits er een impliciete identiteit of verwijzingsconversie van S naar T.
  • 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_typeT als deze een impliciete identiteit of verwijzingsconversie heeft naar een T₀ en T₀ een identiteitsconversie Tnaar .
  • Van elke reference_type naar een interface of gedelegeerd type T als deze een impliciete identiteit of verwijzingsconversie heeft naar een interface of gedelegeerd type T₀ en T₀ variantie-converteerbaar is (§18.2.3.3) naar T.
  • 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 andere I₀ , en I₀ is variantie-converteerbaar (§18.2.3.3) tot I.
  • 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 interface I, met een boksklasse genaamd S_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 type S bestaat nu uit het uitvoeren van de expressie new S_Boxing(v) en het retourneren van het resulterende exemplaar als een waarde van het doeltype van de conversie. De verklaringen

S 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 runtimetype Sen een runtimetypecontrole met behulp van de is 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 volgende

struct Point
{
    public int x, y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    void M() 
    {
        Point p = new Point(10, 10);
        object box = p;
        p.x = 20;
        Console.Write(((Point)box).x);
    }
}

voert de waarde 10 uit op de console omdat de impliciete boksbewerking die plaatsvindt in de toewijzing van p de box waarde die p moet worden gekopieerd, wordt uitgevoerd. Was Point een in plaats daarvan gedeclareerd class , de waarde 20 zou uitvoer zijn omdat p en box 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 objecten 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 en i 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 van d(string) naar het doeltype. Er wordt een conversie gevonden naar string , maar niet naar int.

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, , byteshortushort, , uintof ulong, 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 longulong, 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 basisklasse C, van T naar elke basisklasse van Cen van T elke interface die wordt geïmplementeerd door C.
  • Van T naar een interface_typeI in Tde effectieve interfaceset en van T elke basisinterface van I.
  • Van T naar een typeparameter U die T afhankelijk U is van (§15.2.5).

    Opmerking: Aangezien T bekend is dat het een verwijzingstype is, Tis het runtimetype U altijd een referentietype, zelfs als U 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 basisklasse C, van T naar elke basisklasse van Cen van T elke interface die wordt geïmplementeerd door C.

    Opmerking: C dit is een van de typen System.Object, System.ValueTypeof System.Enum (anders T zou het een verwijzingstype zijn). eindnotitie

  • Van T naar een interface_typeI in Tde effectieve interfaceset en van T elke basisinterface van I.

Voor een type_parameterT die niet bekend is als een verwijzingstype, is er een impliciete conversie van T naar een typeparameter U opgegevenT, afhankelijk Uvan. 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, TU 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 verwijzingstype S als het een impliciete conversie naar een verwijzingstype S₀ heeft en S₀ een identiteitsconversie Snaar . Tijdens de uitvoering wordt de conversie op dezelfde manier uitgevoerd als de conversie naar S₀.
  • Van T naar een interfacetype I als deze een impliciete conversie naar een interfacetype I₀heeft en I₀ variantie converteert naar I (§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 Thet 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, Ete 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, t2t4 en t5 zijn allemaal geldig, omdat impliciete conversies bestaan van de elementexpressies naar de bijbehorende elementtypen. De declaratie van t3 is ongeldig, omdat er geen conversie is van null naar int. De declaratie van t5 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 naar byte, ushort, uint, of ulongchar.
  • Van byte naar sbyte of char.
  • Van short naar sbyte, byte, ushort, , , uintof ulongchar.
  • Van ushort naar sbyte, byte, of shortchar.
  • Van int naar sbyte, byte, short, , ushort, , uint, of ulong.char
  • Van uint naar sbyte, byte, short, , , ushortof intchar.
  • Van long naar sbyte, byte, , short, ushort, , int, , uint, , ulongof char.
  • Van ulong naar sbyte, byte, , short, ushort, , int, , uint, , longof char.
  • Van char naar sbyte, byteof short.
  • Van float naar sbyte, byte, , short, ushort, , int, uint, , long, ulong, , , , charof decimal.
  • Van double naar sbyte, byte, , short, ushort, , intuint, long, , ulong, char, , of floatdecimal.
  • Van decimal naar sbyte, byte, , short, ushort, , intuint, long, , ulong, char, , of floatdouble.

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 een System.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
  • 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 een System.OverflowException gegenereerd.
  • Voor een conversie van float of double 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.
    • 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.
  • Voor een conversie van double naar float, wordt de double waarde afgerond op de dichtstbijzijnde float waarde. Als de double waarde te klein is om als een floatweer te geven, wordt het resultaat nul met hetzelfde teken als de waarde. Als de grootte van de double waarde te groot is om als een floatweer te geven, wordt het resultaat oneindig met hetzelfde teken als de waarde. Als de double waarde NaN is, is het resultaat ook NaN.
  • Voor een conversie van float of double naar decimal, wordt de bronwaarde indien nodig geconverteerd naar decimal weergave en afgerond op het dichtstbijzijnde getal (§8.3.8).
    • Als de bronwaarde te klein is om als een decimalweer te geven, wordt het resultaat nul, waarbij het teken van de oorspronkelijke waarde behouden blijft als decimal 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.
  • Voor een conversie van decimal naar of floatdouble wordt de decimal waarde afgerond op het dichtstbijzijnde of double de dichtstbijzijnde float 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 bereik float en double, maar is niet gegarandeerd. Voor decimal representaties zonder infiniteiten of NaN-waarden, en met een kleiner bereik dan float, is het resultaat van een conversie van decimal of naar of floatdouble nooit oneindig of NaN. eindnotitie

10.3.3 Expliciete opsommingsconversies

De expliciete opsommingsconversies zijn:

  • Vansbyte, byte, short, ushort, , int, uint, longulongchar, float, of doubledecimal naar een enum_type.
  • Van elke enum_type tot , , , , sbytebyte, , short, , , ushortintuintlongof . ulongcharfloatdoubledecimal
  • 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 Eint met en het onderliggende type , wordt een conversie van E naar byte verwerkt als een expliciete numerieke conversie (§10.3.2E§10.2.3) van byte naar int. 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_typeS tot elke class_typeT, opgegeven S is een basisklasse van T.
  • Van elke S tot een T, S wordt niet verzegeld en S geleverd wordt niet geïmplementeerdT.
  • Van elke S tot een T, die wordt geleverd, T wordt niet verzegeld of geleverd T implementeertS.
  • Van elke interface_typeS tot een interface_typeT, S die niet is afgeleid van T.
  • Van een array_typeS met een elementtype Sᵢ tot een array_typeT met een elementtype Tᵢ, mits alle volgende waar zijn:
    • S en T verschilt alleen in elementtype. Met andere woorden, S en T hebben hetzelfde aantal dimensies.
    • Er bestaat een expliciete verwijzingsconversie van Sᵢ naar Tᵢ.
  • 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[] naar System.Collections.Generic.IList<T>. System.Collections.Generic.IReadOnlyList<T>ST
  • Van System.Collections.Generic.IList<S>, System.Collections.Generic.IReadOnlyList<S>en hun basisinterfaces naar een enkeldimensionaal matrixtype T[], mits er een identiteitsconversie of expliciete verwijzingsconversie van S naar T is.
  • Van System.Delegate en de interfaces die worden geïmplementeerd in elke delegate_type.
  • Van een verwijzingstype naar een verwijzingstype ST als het een expliciete verwijzingsconversie van S een verwijzingstype naar een verwijzingstype T₀ heeft en T₀ er een identiteitsconversie van T₀ naar T.
  • Van een verwijzingstype S naar een interface of gedelegeerd type T als er een expliciete verwijzingsconversie is van S een interface of gemachtigde type T₀ en T₀ een variantie-converteerbaar naar of T variantie-converteerbaar T is naar T₀§18.2.3.3.
  • Van D<S₁...Sᵥ> waar D<T₁...Tᵥ>D<X₁...Xᵥ> een algemeen gemachtigde type is, D<S₁...Sᵥ> is niet compatibel met of identiek D<T₁...Tᵥ>aan, en voor elk type parameter Xᵢ van D de volgende bewaring:
    • Als Xᵢ is invariant, Sᵢ dan is identiek aan Tᵢ.
    • Als Xᵢ covariant is, is er een identiteitsconversie, impliciete verwijzingsconversie of expliciete verwijzingsconversie van Sᵢ naar Tᵢ.
    • Als Xᵢ dit contravariant is, Sᵢ zijn ze Tᵢ identiek of beide verwijzingstypen.
  • 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 nulleen 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 Thet 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, Ete 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 van I naar I₀.
  • 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 ofwel I₀ variance_convertible is of II is variantie-converteerbaar naar I₀ (§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_typeS bestaat uit het uitvoeren van de expressie ((S_Boxing)box).value. De verklaringen

object 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 van T van en naar T elke basisklasse van C naar T.
  • Van elke interface_type tot T.
  • Van T naar een interface_typeI opgegeven is er nog geen impliciete verwijzingsconversie van T naar I.
  • Van een U tot T voorwaarde dat T afhankelijk is U van (§15.2.5).

    Opmerking: Aangezien T het een verwijzingstype is, binnen het bereik van T, is het runtimetype van u altijd een verwijzingstype, zelfs als U 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 van T van en naar T elke basisklasse van C naar T.

    Opmerking: C is een van de typen System.Object, System.ValueTypeof System.Enum (anders T 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 van T naar I. Deze conversie bestaat uit een impliciete boksconversie (§10.2.9) van T naar object gevolgd door een expliciete verwijzingsconversie van object naar I. 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 tot T opgegeven die T afhankelijk U is van (§15.2.5). T Als dit een waardetype is en U een verwijzingstype is, wordt de conversie uitgevoerd als een conversie voor het uitpakken van de vakken. 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 is dit U 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 naar long is toegestaan, kan men gemakkelijk verwachten dat dat X<int>.F(7) zou retourneren 7L. 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 boxed int niet rechtstreeks kan worden geconverteerd naar een long.

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 type B, bestaat er een standaard expliciete conversie van type A naar type B en van type naar type BA. 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₀ en T₀ zijn verschillende typen.
  • Of S₀ is het klasse- T₀ of structtype waarin de operatordeclaratie plaatsvindt.
  • S₀ Noch T₀ een interface_type.
  • Met uitzondering van door de gebruiker gedefinieerde conversies bestaat er geen conversie van S naar T 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 type B, en als noch AB interface_type s zijn , dan A wordt gezegd te omvattenB , en B wordt gezegd te omvatten .A
  • Als een standaard impliciete conversie (§10.4.2) bestaat van een expressie E tot een typeB, en als noch B het type E (indien het een heeft) s zijn, dan E wordt gezegd dat deze omvat door, en wordt gezegd te BBE.
  • 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 Sen S₀T₀.

    • Als E u een type hebt, laat S u dat type zijn.
    • Als S of T null-waardetypen zijn, laat Sᵢ en zijn ze de onderliggende typen, laat ze Tᵢ anders toe Sᵢ en TᵢST, respectievelijk.
    • Als Sᵢ of Tᵢ typeparameters zijn, laat S₀ en zijn ze hun effectieve basisklassen, laat ze T₀ anders toe S₀ en T₀SₓTᵢ, respectievelijk.
  • Zoek de set typen, Dvan waaruit door de gebruiker gedefinieerde conversieoperators worden overwogen. Deze set bestaat uit S₀ (indien S₀ aanwezig en is een klasse of struct), de basisklassen S₀ van (indien S₀ aanwezig en is een klasse) en T₀ (als T₀ het een klasse of struct is). Er wordt alleen een type aan de set D 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 in D die worden omgezet van een type dat omvat E tot een type dat wordt omvat door T. Als U deze leeg is, is de conversie niet gedefinieerd en treedt er een compileertijdfout op.

    • Indien S aanwezig en een van de operators in U converteren van S, dan Sₓ is S.
    • Anders is dit Sₓ het meest omvattende type in de gecombineerde set brontypen van de operators in U. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
  • Zoek het meest specifieke doeltype, Tₓvan de operators in U:

    • Als een van de operators die U worden geconverteerd naar T, dan Tₓ is T.
    • Anders is het Tₓ meest omvattende type in de gecombineerde set doeltypen van de operators in U. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
  • 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 van SₓTₓwaaruit wordt geconverteerd, is dit de meest specifieke conversieoperator.
    • Anders is de conversie dubbelzinnig en treedt er een compilatietijdfout op.
  • Pas ten slotte de conversie toe:

    • Als E het type Sₓnog niet heeft, wordt er een standaard impliciete conversie van E naar Sₓ uitgevoerd.
    • De meest specifieke conversieoperator wordt aangeroepen om van te converteren Sₓ naar Tₓ.
    • Als Tₓ dat niet Thet is, wordt een standaard impliciete conversie van Tₓ naar T uitgevoerd.

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 Sen S₀T₀.
    • Als E u een type hebt, laat S u dat type zijn.
    • Als S of T null-waardetypen zijn, laat Sᵢ en zijn ze de onderliggende typen, laat ze Tᵢ anders toe Sᵢ en TᵢST, respectievelijk.
    • Als Sᵢ of Tᵢ typeparameters zijn, laat S₀ en zijn ze hun effectieve basisklassen, laat ze T₀ anders toe S₀ en T₀SᵢTᵢ, respectievelijk.
  • Zoek de set typen, Dvan waaruit door de gebruiker gedefinieerde conversieoperators worden overwogen. Deze set bestaat uit S₀ (indien S₀ aanwezig en is een klasse of struct), de basisklassen S₀ van (indien S₀ aanwezig en is een klasse), T₀ (als T₀ dit een klasse of struct is) en de basisklassen van T₀ (als T₀ dit een klasse is). A het type wordt alleen toegevoegd aan de set D 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 in D die conversie van een type dat omvat E of omvat door S (indien aanwezig) naar een type dat omvat of omvat door T. Als U deze leeg is, is de conversie niet gedefinieerd en treedt er een compileertijdfout op.
  • Zoek het meest specifieke brontype, Sₓvan de operators in U:
    • Als S bestaat en een van de operators die worden U geconverteerd van S, dan Sₓ is S.
    • Als een van de operators die U worden geconverteerd van typen die omvatten E, is dit Sₓ 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 in U. Als precies één meest omvattend type niet kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
  • Zoek het meest specifieke doeltype, Tₓvan de operators in U:
    • Als een van de operators die U worden geconverteerd naar T, dan Tₓ is T.
    • Als een van de operators die U worden geconverteerd naar typen die zijn opgenomen in T, is dit Tₓ 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 in U. Als er geen meest omvattend type kan worden gevonden, is de conversie dubbelzinnig en treedt er een compilatiefout op.
  • 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 van SₓTₓwaaruit wordt geconverteerd, is dit de meest specifieke conversieoperator.
    • Anders is de conversie dubbelzinnig en treedt er een compilatietijdfout op.
  • Pas ten slotte de conversie toe:
    • Als E dit nog niet het type Sₓheeft, wordt een standaard expliciete conversie van E naar Sₓ uitgevoerd.
    • De meest specifieke door de gebruiker gedefinieerde conversieoperator wordt aangeroepen om te converteren van Sₓ naar Tₓ.
    • Als Tₓ dat niet Tzo is, wordt een standaard expliciete conversie van Tₓ naar T uitgevoerd.

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? naar T?
  • Een impliciete of expliciete conversie van S naar T?
  • Een expliciete conversie van S? naar T.

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? naar T?:
    • Als de bronwaarde null is (HasValue eigenschap is false), is het resultaat de null-waarde van het type T?.
    • Anders wordt de conversie geëvalueerd als uitpakken van S? naar S, gevolgd door de onderliggende conversie van S naar T, gevolgd door een terugloop van T naar T?.
  • Als de null-conversie van S naar is T?, wordt de conversie geëvalueerd als de onderliggende conversie van S naar T gevolgd door een terugloop van T naar T?.
  • Als de null-conversie van S? naar is T, wordt de conversie geëvalueerd als uitpakken van S? naar S gevolgd door de onderliggende conversie van S naar T.

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, DF 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 van D een uitvoerparameter is.
  • Als F er een expliciet getypte parameterlijst is, heeft elke parameter D dezelfde modifiers als de bijbehorende parameter in F en bestaat er een identiteitsconversie tussen de bijbehorende parameter in F.
  • Als F er een impliciet getypte parameterlijst is, D heeft u geen verwijzings- of uitvoerparameters.
  • Als de hoofdtekst F een expressie is en D ongeldig retourtype F asynchroon is en D een «TaskType» retourtype (§15.15.15.1) heeft, is de FDhoofdtekst F 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 en D een «TaskType» retourtype heeft, krijgt elke parameter F het type van de overeenkomstige parameter in D, dan is de hoofdtekst F van een geldig blok (w.r.t §13.3) waarin geen return instructie een expressie aangeeft.
  • Als de hoofdtekst F van een expressie is en F is en D een niet-retourtype voidT heeft, F asynchroon is en D een «TaskType»<T> retourtype (§15.15.15.1) heeft, is de FDhoofdtekst F 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 en D een niet-ongeldig retourtype Theeft, F asynchroon is en D een «TaskType»<T> retourtype heeft, krijgt elke parameter F het type van de bijbehorende parameter inD, dan is de hoofdtekst F een geldig instructieblok (w.r.t §13.3) met een niet-bereikbaar eindpunt waarin elke retourinstructie een expressie aangeeft die impliciet converteerbaar is naar T.

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 type A gebruikt en een waarde van het type Rretourneert:

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, wanneer x het type intis opgegeven, x + 1 een geldige expressie is die impliciet kan worden omgezet in type int.

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 type int) impliciet converteert naar type double.

De derde toewijzing is echter een compilatiefout omdat, wanneer x het opgegeven type doubleis, het resultaat van x + 1 (van het type double) niet impliciet converteerbaar is naar type int.

De vierde toewijzing converteert de anonieme asynchrone functie naar het gemachtigde type Func<int, Task<int>> omdat het resultaat van x + 1 (van het type int) impliciet wordt omgezet in het effectieve retourtype int van de asynchrone lambda, dat een retourtype Task<int>heeft.

eindvoorbeeld

Een lambda-expressie F is compatibel met een expressiestructuurtype Expression<D> als F deze compatibel is met het type Dgemachtigde. 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 formulier E(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, outof ref) van de bijbehorende parameter in het parameter_list van D , met uitzondering van parameters van het type dynamic, waarbij de bijbehorende expressie het type object heeft in plaats van dynamic.
    • 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
  • Een conversie wordt beschouwd als het algoritme van §12.8.10.2D
  • Als de geselecteerde methode M een exemplaarmethode is, bepaalt de exemplaarexpressie die is E 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 methodegroep F te converteren naar een waarde van het type D1.

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 Eof 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 een System.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 nullhet 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.