Konverteringar i Visual Basic

Konvertering är processen att ändra ett värde från en typ till en annan. Till exempel kan ett värde av typen Integer konverteras till ett värde av typen Double, eller så kan ett värde av typen Derived konverteras till ett värde av typen Base, förutsatt att Base och Derived är båda klasserna och Derived ärver från Base. Konverteringar kanske inte kräver att själva värdet ändras (som i det senare exemplet), eller så kan de kräva betydande ändringar i värderepresentationen (som i det tidigare exemplet).

Konverteringar kan antingen vara bredare eller smalare. En utvidgad konvertering är en konvertering från en typ till en annan typ vars värdedomän är minst lika stor, om inte större, än den ursprungliga typens värdedomän. Utvidgning av konverteringar får aldrig misslyckas. En begränsad konvertering är en konvertering från en typ till en annan typ vars värdedomän antingen är mindre än den ursprungliga typens värdedomän eller tillräckligt orelaterad att extra försiktighet måste iakttas vid konverteringen (till exempel vid konvertering från Integer till String). Att begränsa konverteringar, vilket kan leda till informationsförlust, kan misslyckas.

Identitetskonverteringen (dvs. en konvertering från en typ till sig själv) och standardvärdekonverteringen (dvs. en konvertering från Nothing) definieras för alla typer.

Implicita och explicita konverteringar

Konverteringar kan vara antingen implicita eller explicita. Implicita konverteringar sker utan någon särskild syntax. Följande är ett exempel på implicit konvertering av ett Integer värde till ett Long värde:

Module Test
    Sub Main()
        Dim intValue As Integer = 123
        Dim longValue As Long = intValue

        Console.WriteLine(intValue & " = " & longValue)
    End Sub
End Module

Explicita konverteringar kräver å andra sidan gjutna operatorer. Om du försöker göra en explicit konvertering av ett värde utan en cast-operator uppstår ett kompileringsfel. I följande exempel används en explicit konvertering för att konvertera ett Long värde till ett Integer värde.

Module Test
    Sub Main()
        Dim longValue As Long = 134
        Dim intValue As Integer = CInt(longValue)

        Console.WriteLine(longValue & " = " & intValue)
    End Sub
End Module

Uppsättningen implicita konverteringar beror på kompileringsmiljön och -instruktionen Option Strict . Om strikt semantik används kan endast bredare konverteringar ske implicit. Om tillåtande semantik används kan alla bredare och smala konverteringar (med andra ord alla konverteringar) ske implicit.

Booleska konverteringar

Även om Boolean det inte är en numerisk typ har den begränsade konverteringar till och från de numeriska typerna som om det vore en uppräkningstyp. Literalen True konverteras till literalen 255 för Byte, 65535 för UShort, 4294967295 för UInteger, 18446744073709551615 och ULongtill uttrycket -1 för SByte, Short, Integer, Long, Decimal, och SingleDouble. Literalen False konverteras till literalen 0. Ett numeriskt värde utan värde konverteras till literalen False. Alla andra numeriska värden konverteras till literalen True.

Det finns en begränsad konvertering från boolesk till Sträng, som konverterar till antingen System.Boolean.TrueString eller System.Boolean.FalseString. Det finns också en begränsad konvertering från String till Boolean: om strängen var lika TrueString med eller FalseString (i den aktuella kulturen, skiftlägesokänsligt) använder den lämpligt värde. Annars försöker den parsa strängen som en numerisk typ (i hex eller oktal om möjligt, annars som en flyttal) och använder ovanstående regler, annars genererar System.InvalidCastExceptionden .

Numeriska konverteringar

Numeriska konverteringar finns mellan typerna Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, Decimal, Single och och Double, och alla uppräknade typer. När de konverteras behandlas uppräknade typer som om de vore deras underliggande typer. När du konverterar till en uppräknad typ krävs inte källvärdet för att överensstämma med den uppsättning värden som definierats i den uppräknade typen. Till exempel:

Enum Values
    One
    Two
    Three
End Enum

Module Test
    Sub Main()
        Dim x As Integer = 5

        ' OK, even though there is no enumerated value for 5.
        Dim y As Values = CType(x, Values)
    End Sub
End Module

Numeriska konverteringar bearbetas vid körning enligt följande:

  • För en konvertering från en numerisk typ till en bredare numerisk typ konverteras värdet helt enkelt till den bredare typen. Konverteringar från UInteger, Integer, ULong, Longeller Decimal till Single eller Double avrundas till närmaste Single värde eller Double värde. Även om den här konverteringen kan orsaka en förlust av precision, kommer den aldrig att orsaka förlust av storlek.

  • För en konvertering från en integraltyp till en annan integraltyp, eller från Single, Doubleeller Decimal till en integrerad typ, beror resultatet på om heltalsöverflödeskontroll är på:

    Om heltalsspill kontrolleras:

    • Om källan är en integrerad typ lyckas konverteringen om källargumentet ligger inom måltypens intervall. Konverteringen utlöser ett System.OverflowException undantag om källargumentet ligger utanför måltypens intervall.

    • Om källan är Single, Double, eller Decimal, avrundas källvärdet upp eller ned till närmaste integralvärde, och det här integralvärdet blir resultatet av konverteringen. Om källvärdet är lika nära två integralvärden avrundas värdet till det värde som har ett jämnt tal i den minst signifikanta sifferpositionen. Om det resulterande integralvärdet ligger utanför måltypens intervall genereras ett System.OverflowException undantag.

    Om heltalsspill inte kontrolleras:

    • Om källan är en integrerad typ lyckas konverteringen alltid och består helt enkelt av att ta bort de viktigaste bitarna av källvärdet.

    • Om källan är Single, Double, eller Decimal, lyckas konverteringen alltid och består helt enkelt av att avrunda källvärdet mot närmaste integralvärde. Om källvärdet är lika nära två integralvärden avrundas värdet alltid till det värde som har ett jämnt tal i den minst signifikanta sifferpositionen.

  • För en konvertering från Double till SingleDouble avrundas värdet till närmaste Single värde. Om värdet Double är för litet för att representeras som en Singleblir resultatet positiv noll eller negativ nolla. Om värdet Double är för stort för att representeras som en Singleblir resultatet positiv oändlighet eller negativ oändlighet. Om värdet Double är NaNär resultatet också NaN.

  • För en konvertering från Single eller Double till Decimalkonverteras källvärdet till Decimal representation och avrundas till närmaste tal efter den 28:e decimalplatsen om det behövs. Om källvärdet är för litet för att representeras som en Decimalblir resultatet noll. Om källvärdet är NaN, oändlighet eller för stort för att representeras som ett Decimalgenereras ett System.OverflowException undantag.

  • För en konvertering från Double till SingleDouble avrundas värdet till närmaste Single värde. Om värdet Double är för litet för att representeras som en Singleblir resultatet positiv noll eller negativ nolla. Om värdet Double är för stort för att representeras som en Singleblir resultatet positiv oändlighet eller negativ oändlighet. Om värdet Double är NaNär resultatet också NaN.

Referenskonverteringar

Referenstyper kan konverteras till en bastyp och vice versa. Konverteringar från en bastyp till en mer härledd typ lyckas bara vid körning om värdet som konverteras är ett null-värde, själva den härledda typen eller en mer härledd typ.

Klass- och gränssnittstyper kan castas till och från vilken gränssnittstyp som helst. Konverteringar mellan en typ och en gränssnittstyp lyckas bara vid körning om de faktiska typerna har en arvs- eller implementeringsrelation. Eftersom en gränssnittstyp alltid innehåller en instans av en typ som härleds från Objectkan en gränssnittstyp också alltid castas till och från Object.

Observera. Det är inte ett fel att konvertera en NotInheritable klass till och från gränssnitt som den inte implementerar eftersom klasser som representerar COM-klasser kan ha gränssnittsimplementeringar som inte är kända förrän körningstiden.

Om en referenskonvertering misslyckas vid körningen genereras ett System.InvalidCastException undantag.

Referensavvikelsekonverteringar

Allmänna gränssnitt eller ombud kan ha parametrar av varianttyp som tillåter konverteringar mellan kompatibla varianter av typen. Vid körningen lyckas därför en konvertering från en klasstyp eller en gränssnittstyp till en gränssnittstyp som är variantkompatibel med en gränssnittstyp som den ärver från eller implementerar. På samma sätt kan ombudstyper castas till och från variantkompatibla ombudstyper. Till exempel ombudstypen

Delegate Function F(Of In A, Out R)(a As A) As R

skulle tillåta en konvertering från F(Of Object, Integer) till F(Of String, Integer). Det vill säga en delegat F som tar Object kan användas på ett säkert sätt som en delegat F som tar String. När ombudet anropas förväntar sig målmetoden ett objekt och en sträng är ett objekt.

En allmän delegat- eller gränssnittstyp S(Of S1,...,Sn) sägs vara variantkompatibel med ett allmänt gränssnitt eller en delegattyp T(Of T1,...,Tn) om:

  • S och T är båda konstruerade av samma generiska typ U(Of U1,...,Un).

  • För varje typparameter Ux:

    • Om typparametern deklarerades utan varians Sx måste den Tx vara av samma typ.

    • Om typparametern deklarerades In måste det finnas en bredare identitet, standard, referens, matris eller typparameterkonvertering från Sx till Tx.

    • Om typparametern deklarerades Out måste det finnas en bredare identitet, standard, referens, matris eller typparameterkonvertering från Tx till Sx.

När du konverterar från en klass till ett generiskt gränssnitt med parametrar av varianttyp är konverteringen tvetydig om klassen implementerar mer än ett variantkompatibelt gränssnitt om det inte finns en konvertering som inte är en variant. Till exempel:

Class Base
End Class

Class Derived1
    Inherits Base
End Class

Class Derived2
    Inherits Base
End Class

Class OneAndTwo
    Implements IEnumerable(Of Derived1)
    Implements IEnumerable(Of Derived2)
End Class

Class BaseAndOneAndTwo
    Implements IEnumerable(Of Base)
    Implements IEnumerable(Of Derived1)
    Implements IEnumerable(Of Derived2)
End Class

Module Test
    Sub Main()
        ' Error: conversion is ambiguous
        Dim x As IEnumerable(Of Base) = New OneAndTwo()

        ' OK, will pick up the direct implementation of IEnumerable(Of Base)
        Dim y as IEnumerable(Of Base) = New BaseAndOneAndTwo()
    End Sub
End Module

Anonyma ombudskonverteringar

När ett uttryck som klassificeras som en lambda-metod omklassificeras som ett värde i en kontext där det inte finns någon måltyp (till exempel Dim x = Function(a As Integer, b As Integer) a + b), eller där måltypen inte är en ombudstyp, är typen av det resulterande uttrycket en anonym delegattyp som motsvarar lambda-metodens signatur. Den här anonyma delegattypen har en konvertering till alla kompatibla ombudstyper: en kompatibel delegattyp är valfri delegattyp som kan skapas med ett uttryck för att skapa ombud med metoden för anonym delegattyp Invoke som parameter. Till exempel:

' Anonymous delegate type similar to Func(Of Object, Object, Object)
Dim x = Function(x, y) x + y

' OK because delegate type is compatible
Dim y As Func(Of Integer, Integer, Integer) = x

Observera att typerna System.Delegate och System.MulticastDelegate inte själva betraktas som ombudstyper (även om alla ombudstyper ärver från dem). Observera också att konverteringen från anonym delegattyp till en kompatibel delegattyp inte är en referenskonvertering.

Matriskonverteringar

Förutom de konverteringar som definieras i matriser på grund av att de är referenstyper finns det flera särskilda konverteringar för matriser.

För två typer A och B, om de båda är referenstyper eller typparametrar som inte är kända för att vara värdetyper, och om A har en referens, matris eller typparameterkonvertering till B, finns det en konvertering från en matris av typen A till en matris av typen B med samma rangordning. Den här relationen kallas matriskovarians. I synnerhet matriskovarians innebär att ett element i en matris vars elementtyp faktiskt kan B vara ett element i en matris vars elementtyp är A, förutsatt att både A och B är referenstyper och som B har en referenskonvertering eller matriskonvertering till A. I följande exempel orsakar det andra anropet ett F undantag eftersom den faktiska elementtypen b är String, inte Object:System.ArrayTypeMismatchException

Module Test
    Sub F(ByRef x As Object)
    End Sub

    Sub Main()
        Dim a(10) As Object
        Dim b() As Object = New String(10) {}
        F(a(0)) ' OK.
        F(b(1)) ' Not allowed: System.ArrayTypeMismatchException.
   End Sub
End Module

På grund av matriskovarians inkluderar tilldelningar till element av referenstypmatriser en körningskontroll som säkerställer att värdet som tilldelas till matriselementet faktiskt är av en tillåten typ.

Module Test
    Sub Fill(array() As Object, index As Integer, count As Integer, _
            value As Object)
        Dim i As Integer

        For i = index To (index + count) - 1
            array(i) = value
        Next i
    End Sub

    Sub Main()
        Dim strings(100) As String

        Fill(strings, 0, 101, "Undefined")
        Fill(strings, 0, 10, Nothing)
        Fill(strings, 91, 10, 0)
    End Sub
End Module

I det här exemplet innehåller tilldelningen till array(i) i -metoden Fill implicit en körningskontroll som säkerställer att objektet som refereras av variabeln value är antingen Nothing eller en instans av en typ som är kompatibel med den faktiska elementtypen för matrisen array. I metoden Mainlyckas de två första anropen av metoden Fill , men det tredje anropet gör att ett System.ArrayTypeMismatchException undantag utlöses när den första tilldelningen körs till array(i). Undantaget beror på att en Integer inte kan lagras i en String matris.

Om en av matriselementtyperna är en typparameter vars typ visar sig vara en värdetyp vid körningen genereras ett System.InvalidCastException undantag. Till exempel:

Module Test
    Sub F(Of T As U, U)(x() As T)
        Dim y() As U = x
    End Sub

    Sub Main()
        ' F will throw an exception because Integer() cannot be
        ' converted to Object()
        F(New Integer() { 1, 2, 3 })
    End Sub
End Module

Konverteringar finns också mellan en matris av en uppräknad typ och en matris av den uppräknade typens underliggande typ eller en matris av en annan uppräknad typ med samma underliggande typ, förutsatt att matriserna har samma rangordning.

Enum Color As Byte
    Red
    Green
    Blue
End Enum

Module Test
    Sub Main()
        Dim a(10) As Color
        Dim b() As Integer
        Dim c() As Byte

        b = a    ' Error: Integer is not the underlying type of Color
        c = a    ' OK
        a = c    ' OK
    End Sub
End Module

I det här exemplet konverteras en matris med Color till och från en matris av Byteden underliggande typen . Color Konverteringen till en matris med Integerär dock ett fel eftersom Integer den inte är den underliggande typen av Color.

En matris av typen A() rank-1 har också en matriskonvertering till samlingsgränssnittstyperna IList(Of B), IReadOnlyList(Of B), ICollection(Of B)IReadOnlyCollection(Of B) och IEnumerable(Of B) finns i System.Collections.Generic, så länge något av följande är sant:

  • A och B är både referenstyper eller typparametrar som inte är kända för att vara värdetyper och A har en bredare referens, matris eller typparameterkonvertering till B; eller
  • A och B är båda uppräknade typer av samma underliggande typ, eller
  • en av A och B är en uppräknad typ, och den andra är dess underliggande typ.

Alla matriser av typen A med valfri rangordning har också en matriskonvertering till de icke-generiska samlingsgränssnittstyperna IListoch ICollectionIEnumerable finns i System.Collections.

Du kan iterera över de resulterande gränssnitten med hjälp av For Eacheller genom att GetEnumerator anropa metoderna direkt. När det gäller matriser med rangordning 1 konverteras generiska eller icke-generiska former av IList eller ICollection, är det också möjligt att hämta element efter index. När det gäller matriser med rangordning 1 som konverterats till generiska eller icke-generiska former av IListgår det också att ange element efter index, med samma körningsmatriskovarianskontroller som beskrivs ovan. Beteendet för alla andra gränssnittsmetoder är odefinierat av VB-språkspecifikationen. det är upp till den underliggande körningen.

Konverteringar av värdetyp

Ett värdetypsvärde kan konverteras till en av dess basreferenstyper eller en gränssnittstyp som det implementerar via en process som kallas boxning. När ett värdetypsvärde boxas kopieras värdet från platsen där det finns till .NET Framework-heapen. En referens till den här platsen på heapen returneras sedan och kan lagras i en referenstypvariabel. Den här referensen kallas även för en boxad instans av värdetypen. Den inramade instansen har samma semantik som en referenstyp i stället för en värdetyp.

Boxade värdetyper kan konverteras tillbaka till sin ursprungliga värdetyp via en process som kallas unboxing. När en boxad värdetyp är oboxad kopieras värdet från heapen till en variabelplats. Från och med då fungerar det som om det var en värdetyp. När du avboxar en värdetyp måste värdet vara ett null-värde eller en instans av värdetypen. Annars utlöses ett System.InvalidCastException undantag. Om värdet är en instans av en uppräknad typ kan det värdet också tas bort till den uppräknade typens underliggande typ eller en annan uppräkningstyp som har samma underliggande typ. Ett null-värde behandlas som om det vore literalen Nothing.

Om du vill ha stöd för nullbara värdetyper behandlas värdetypen System.Nullable(Of T) särskilt när boxning och avboxning utförs. Boxning av ett värde av typen Nullable(Of T) resulterar i ett boxat värde av typen T om värdets HasValue egenskap är True eller ett värde för Nothing om värdets HasValue egenskap är False. Om du tar bort ett värde av typen T för att Nullable(Of T) resultera i en instans av Nullable(Of T) vars Value egenskap är det boxade värdet och vars HasValue egenskap är True. Värdet Nothing kan tas bort till Nullable(Of T) för alla T och resulterar i ett värde vars HasValue egenskap är False. Eftersom boxade värdetyper fungerar som referenstyper är det möjligt att skapa flera referenser till samma värde. För primitiva typer och uppräknade typer är detta irrelevant eftersom instanser av dessa typer är oföränderliga. Det är alltså inte möjligt att ändra en boxad instans av dessa typer, så det går inte att observera att det finns flera referenser till samma värde.

Strukturer kan å andra sidan vara föränderliga om dess instansvariabler är tillgängliga eller om dess metoder eller egenskaper ändrar instansvariablerna. Om en referens till en boxad struktur används för att ändra strukturen ser alla referenser till den boxade strukturen ändringen. Eftersom det här resultatet kan vara oväntat, klonas automatiskt ett värde som skrivs som Object kopieras från en plats till en annan på heapen i stället för att bara deras referenser kopieras. Till exempel:

Class Class1
    Public Value As Integer = 0
End Class

Structure Struct1
    Public Value As Integer
End Structure

Module Test
    Sub Main()
        Dim val1 As Object = New Struct1()
        Dim val2 As Object = val1

        val2.Value = 123

        Dim ref1 As Object = New Class1()
        Dim ref2 As Object = ref1

        ref2.Value = 123

        Console.WriteLine("Values: " & val1.Value & ", " & val2.Value)
        Console.WriteLine("Refs: " & ref1.Value & ", " & ref2.Value)
    End Sub
End Module

Programmets utdata är:

Values: 0, 123
Refs: 123, 123

Tilldelningen till fältet för den lokala variabeln val2 påverkar inte fältet för den lokala variabeln val1 eftersom när den rutade Struct1 tilldelades till val2gjordes en kopia av värdet. Tilldelningen ref2.Value = 123 påverkar däremot det objekt som både ref1 och ref2 refererar till.

Observera. Strukturkopiering görs inte för inramade strukturer som skrivs eftersom System.ValueType det inte går att fördröja bindningen från System.ValueType.

Det finns ett undantag till regeln att boxade värdetyper kopieras vid tilldelning. Om en rutad värdetypsreferens lagras inom en annan typ kopieras inte den inre referensen. Till exempel:

Structure Struct1
    Public Value As Object
End Structure

Module Test
    Sub Main()
        Dim val1 As Struct1
        Dim val2 As Struct1

        val1.Value = New Struct1()
        val1.Value.Value = 10

        val2 = val1
        val2.Value.Value = 123
        Console.WriteLine("Values: " & val1.Value.Value & ", " & _
            val2.Value.Value)
    End Sub
End Module

Programmets utdata är:

Values: 123, 123

Det beror på att det inre boxade värdet inte kopieras när värdet kopieras. Därför både val1.Value och val2.Value har en referens till samma boxade värdetyp.

Observera. Det faktum att interna boxade värdetyper inte kopieras är en begränsning av .NET-typsystemet – för att säkerställa att alla interna boxade värdetyper kopierades när ett värde av typen Object kopierades skulle vara oöverkomligt dyrt.

Som tidigare beskrivits kan boxade värdetyper endast tas bort till sin ursprungliga typ. Boxade primitiva typer behandlas dock speciellt när de skrivs som Object. De kan konverteras till alla andra primitiva typer som de har en konvertering till. Till exempel:

Module Test
    Sub Main()
        Dim o As Object = 5
        Dim b As Byte = CByte(o)  ' Legal
        Console.WriteLine(b) ' Prints 5
    End Sub
End Module

Normalt sett gick det inte att ta bort det rutorade Integer värdet 5 till en Byte variabel. Men eftersom Integer och Byte är primitiva typer och har en konvertering tillåts konverteringen.

Observera att konverteringen av en värdetyp till ett gränssnitt skiljer sig från ett allmänt argument som är begränsat till ett gränssnitt. När du kommer åt gränssnittsmedlemmar på en begränsad typparameter (eller anropar metoder på Object), sker inte boxning som när en värdetyp konverteras till ett gränssnitt och en gränssnittsmedlem nås. Anta till exempel att ett gränssnitt ICounter innehåller en metod Increment som kan användas för att ändra ett värde. Om ICounter används som en begränsning anropas implementeringen av Increment metoden med en referens till variabeln som Increment anropades, inte en rutad kopia:

Interface ICounter
    Sub Increment()
    ReadOnly Property Value() As Integer
End Interface

Structure Counter
    Implements ICounter

    Dim _value As Integer

    Property Value() As Integer Implements ICounter.Value
        Get
            Return _value
        End Get
    End Property

    Sub Increment() Implements ICounter.Increment
       value += 1
    End Sub
End Structure

Module Test
      Sub Test(Of T As ICounter)(x As T)
         Console.WriteLine(x.value)
         x.Increment()                     ' Modify x
         Console.WriteLine(x.value)
         CType(x, ICounter).Increment()    ' Modify boxed copy of x
         Console.WriteLine(x.value)
      End Sub

      Sub Main()
         Dim x As Counter
         Test(x)
      End Sub
End Module

Det första anropet till Increment modifierar värdet i variabeln x. Detta motsvarar inte det andra anropet till Increment, som ändrar värdet i en rutad kopia av x. Därför är programmets utdata:

0
1
1

Konverteringar av null-värdetyp

En värdetyp T kan konverteras till och från den nullbara versionen av typen , T?. Konverteringen från T? till T genererar ett System.InvalidOperationException undantag om värdet som konverteras är Nothing. T? Dessutom har en konvertering till en typ S om T har en inbyggd konvertering till S. Och om S är en värdetyp finns följande inbyggda konverteringar mellan T? och S?:

  • En konvertering av samma klassificering (begränsa eller bredda) från T? till S?.

  • En konvertering av samma klassificering (begränsa eller bredda) från T till S?.

  • En begränsad konvertering från S? till T.

Det finns till exempel en inbyggd breddningskonvertering från Integer? till Long? eftersom det finns en inbyggd breddningskonvertering från Integer till Long:

Dim i As Integer? = 10
Dim l As Long? = i

När du konverterar från T? till S?, om värdet T? för är Nothing, blir Nothingvärdet S? för . När du konverterar från till eller till , om värdet T? för eller S? är Nothing, genereras ett System.InvalidCastException undantag.ST?TS?

På grund av beteendet för den underliggande typen System.Nullable(Of T)är resultatet ett boxat värde av typen T, inte ett boxat värde av typen T?, när en värdetyp T? som kan vara null är rutad. Och omvänt, när du avmarkerar en nullbar värdetyp T?, kommer värdet att omslutas av System.Nullable(Of T)och Nothing tas bort till ett null-värde av typen T?. Till exempel:

Dim i1? As Integer = Nothing
Dim o1 As Object = i1

Console.WriteLine(o1 Is Nothing)                    ' Will print True
o1 = 10
i1 = CType(o1, Integer?)
Console.WriteLine(i1)                               ' Will print 10

En bieffekt av det här beteendet är att en nullbar värdetyp T? verkar implementera alla gränssnitt för , eftersom konvertering av Ten värdetyp till ett gränssnitt kräver att typen boxas. Som ett resultat, T? är konvertibel till alla gränssnitt som T är konvertibla till. Det är dock viktigt att notera att en nullbar värdetyp T? faktiskt inte implementerar gränssnitten för för allmän kontroll eller reflektion av T begränsningar. Till exempel:

Interface I1
End Interface

Structure T1
    Implements I1
    ...
End Structure

Module Test
    Sub M1(Of T As I1)(ByVal x As T)
    End Sub

    Sub Main()
        Dim x? As T1 = Nothing
        Dim y As I1 = x                ' Valid
        M1(x)                          ' Error: x? does not satisfy I1 constraint
    End Sub
End Module

Strängkonverteringar

Konvertering till CharString resulterar i en sträng vars första tecken är teckenvärdet. Konvertering till StringChar resulterar i ett tecken vars värde är det första tecknet i strängen. Om du konverterar en matris med Char till String resulterar det i en sträng vars tecken är elementen i matrisen. Konvertering till String en matris med Char resultat i en matris med tecken vars element är strängens tecken.

De exakta konverteringarna mellan String och Boolean, Byte, SByte, UShort, Short, UInteger, Integer, ULong, , DecimalLong, , Single, Double, och Datevice versa, ligger utanför omfånget för den här specifikationen och är implementeringsberoende med undantag för en detalj. Strängkonverteringar tar alltid hänsyn till den aktuella kulturen i körningsmiljön. Därför måste de utföras vid körning.

Breddning av konverteringar

Vidgade konverteringar flödar aldrig över, men kan medföra en förlust av precision. Följande konverteringar utvidgar konverteringarna:

Identitets-/standardkonverteringar

  • Från en typ till sig själv.

  • Från en anonym delegattyp som genererats för en lambda-metodomklassificering till valfri delegattyp med en identisk signatur.

  • Från literalen Nothing till en typ.

Numeriska konverteringar

  • Från Byte till UShort, Short, UInteger, Integer, ULong, Long, Decimal, eller SingleDouble.

  • Från SByte till Short, Integer, Long, Decimal, Singleeller Double.

  • Från UShort till UInteger, Integer, ULong, Long, Decimal, Singleeller Double.

  • Från Short till Integer, Long, DecimalSingle eller Double.

  • Från UInteger till ULong, Long, Decimal, Singleeller Double.

  • Från Integer till Long, Decimaleller SingleDouble.

  • Från ULong till Decimal, Singleeller Double.

  • Från Long till Decimal, Single eller Double.

  • Från Decimal till Single eller Double.

  • Från Single till Double.

  • Från literalen 0 till en uppräknad typ. (Obs! Konverteringen från 0 till valfri uppräkningstyp breddas för att förenkla testningsflaggor. Om Values till exempel är en uppräknad typ med ett värde Onekan du testa en variabel v av typen Values genom att säga (v And Values.One) = 0.)

  • Från en uppräknad typ till dess underliggande numeriska typ, eller till en numerisk typ som dess underliggande numeriska typ har en bredare konvertering till.

  • Från ett konstant uttryck av typen ULong, Long, UInteger, Integer, UShort, Short, , Byteeller SByte till en smalare typ, förutsatt att värdet för konstantuttrycket ligger inom måltypens intervall. (Obs! Konverteringar från UInteger eller Integer till Single, ULong eller LongSingleDoubletill eller Decimal till Single eller Double kan orsaka en förlust av precision, men kommer aldrig att orsaka en förlust av omfattning. De andra bredare numeriska konverteringarna förlorar aldrig någon information.)

Referenskonverteringar

  • Från en referenstyp till en bastyp.

  • Från en referenstyp till en gränssnittstyp, förutsatt att typen implementerar gränssnittet eller ett variantkompatibelt gränssnitt.

  • Från en gränssnittstyp till Object.

  • Från en gränssnittstyp till en variantkompatibel gränssnittstyp.

  • Från en ombudstyp till en variantkompatibel delegattyp. (Obs! Många andra referenskonverteringar är underförstådda av dessa regler. Anonyma ombud är till exempel referenstyper som ärver från System.MulticastDelegate. Matristyper är referenstyper som ärver från System.Array; anonyma typer är referenstyper som ärver från System.Object.)

Anonyma ombudskonverteringar

  • Från en anonym delegattyp som genererats för en lambda-metodomklassificering till en bredare delegattyp.

Matriskonverteringar

  • Från en matristyp S med en elementtyp Se till en matristyp T med en elementtyp Te, förutsatt att allt av följande är sant:

    • S och T skiljer sig endast i elementtyp.

    • Både Se och Te är referenstyper eller är typparametrar som är kända för att vara en referenstyp.

    • Det finns en bredare referens, matris eller typparameterkonvertering från Se till Te.

  • Från en matristyp S med en uppräknad elementtyp Se till en matristyp T med en elementtyp Te, förutsatt att alla följande är sanna:

    • S och T skiljer sig endast i elementtyp.

    • Te är den underliggande typen av Se.

  • Från en matristyp S av rang 1 med en uppräknad elementtyp Se, till , IReadOnlyList(Of Te), ICollection(Of Te), IReadOnlyCollection(Of Te), och IEnumerable(Of Te), förutsatt att System.Collections.Generic.IList(Of Te)något av följande är sant:

    • Både Se och Te är referenstyper eller är typparametrar som är kända för att vara en referenstyp, och en bredare referens, matris eller typparameterkonvertering finns från Se till Te; eller

    • Te är den underliggande typen av Se; eller

    • Te är identisk med Se

Konverteringar av värdetyp

  • Från en värdetyp till en bastyp.

  • Från en värdetyp till en gränssnittstyp som typen implementerar.

Konverteringar av nullbar värdetyp

  • Från en typ T till typen T?.

  • Från en typ T? till en typ S?, där det finns en bredare konvertering från typen T till typen S.

  • Från en typ T till en typ S?, där det finns en bredare konvertering från typen T till typen S.

  • Från en typ T? till en gränssnittstyp som typen T implementerar.

Strängkonverteringar

  • Från Char till String.

  • Från Char() till String.

Typparameterkonverteringar

  • Från en typparameter till Object.

  • Från en typparameter till en gränssnittstypsbegränsning eller någon gränssnittsvariant som är kompatibel med en begränsning av gränssnittstyp.

  • Från en typparameter till ett gränssnitt som implementeras av en klassbegränsning.

  • Från en typparameter till en gränssnittsvariant som är kompatibel med ett gränssnitt som implementeras av en klassbegränsning.

  • Från en typparameter till en klassbegränsning eller en bastyp för klassvillkoret.

  • Från en typparameter T till en typparameterbegränsning Tx, eller något Tx har en bredare konvertering till.

Begränsa konverteringar

Begränsade konverteringar är konverteringar som inte alltid kan bevisas lyckas, konverteringar som är kända för att eventuellt förlora information och konverteringar mellan domäner av typer som är tillräckligt olika för att förtjäna en begränsad notation. Följande konverteringar klassificeras som begränsade konverteringar:

Booleska konverteringar

  • Från Boolean till Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, Decimal, , Singleeller Double.

  • Från Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, Decimal, , Singleeller Double till Boolean.

Numeriska konverteringar

  • Från Byte till SByte.

  • Från SByte till Byte, UShort, UIntegereller ULong.

  • Från UShort till Byte, SByteeller Short.

  • Från Short till Byte, SByte, UShort, UIntegereller ULong.

  • Från UInteger till Byte, SByte, UShort, Shorteller Integer.

  • Från Integer till Byte, SByte, UShort, Short, UIntegereller ULong.

  • Från ULong till Byte, SByte, UShort, Short, UInteger, Integereller Long.

  • Från Long till Byte, SByte, UShort, Short, UInteger, Integereller ULong.

  • Från Decimal till Byte, SByte, UShort, Short, UInteger, Integer, ULongeller Long.

  • Från Single till Byte, SByte, UShort, Short, UInteger, Integer, ULong, eller LongDecimal.

  • Från Double till Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, , Decimaleller Single.

  • Från en numerisk typ till en uppräknad typ.

  • Från en uppräknad typ till en numerisk typ har dess underliggande numeriska typ en begränsad konvertering till.

  • Från en uppräkningstyp till en annan uppräkningstyp.

Referenskonverteringar

  • Från en referenstyp till en mer härledd typ.

  • Från en klasstyp till en gränssnittstyp, förutsatt att klasstypen inte implementerar gränssnittstypen eller en gränssnittstypvariant som är kompatibel med den.

  • Från en gränssnittstyp till en klasstyp.

  • Från en gränssnittstyp till en annan gränssnittstyp, förutsatt att det inte finns någon arvsrelation mellan de två typerna och förutsatt att de inte är variantkompatibla.

Anonyma ombudskonverteringar

  • Från en anonym delegattyp som genererats för en lambda-metodomklassificering till en smalare delegattyp.

Matriskonverteringar

  • Från en matristyp S med en elementtyp Se, till en matristyp T med en elementtyp Te, förutsatt att allt följande är sant:

    • S och T skiljer sig endast i elementtyp.
    • Både Se och Te är referenstyper eller är typparametrar som inte är kända för att vara värdetyper.
    • Det finns en begränsad referens, matris eller typparameterkonvertering från Se till Te.
  • Från en matristyp S med en elementtyp Se till en matristyp T med en uppräknad elementtyp Te, förutsatt att alla följande är sanna:

    • S och T skiljer sig endast i elementtyp.
    • Se är den underliggande typen av Te , eller så är de båda olika uppräknade typer som delar samma underliggande typ.
  • Från en matristyp S av rang 1 med en uppräknad elementtyp Se, till , IReadOnlyList(Of Te), ICollection(Of Te)IReadOnlyCollection(Of Te) och IEnumerable(Of Te), förutsatt att IList(Of Te)något av följande är sant:

    • Både Se och Te är referenstyper eller är typparametrar som är kända för att vara en referenstyp, och det finns en förträngningsreferens, matris eller typparameterkonvertering från Se till Te; eller
    • Se är den underliggande typen av Te, eller så är de båda olika uppräknade typer som delar samma underliggande typ.

Konverteringar av värdetyp

  • Från en referenstyp till en mer härledd värdetyp.

  • Från en gränssnittstyp till en värdetyp, förutsatt att värdetypen implementerar gränssnittstypen.

Konverteringar av nullbar värdetyp

  • Från en typ T? till en typ T.

  • Från en typ T? till en typ S?, där det finns en begränsad konvertering från typen T till typen S.

  • Från en typ T till en typ S?, där det finns en begränsad konvertering från typen T till typen S.

  • Från en typ S? till en typ T, där det finns en konvertering från typen S till typen T.

Strängkonverteringar

  • Från String till Char.

  • Från String till Char().

  • Från String till Boolean och från Boolean till String.

  • Konverteringar mellan String och Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, , Decimal, Singleeller Double.

  • Från String till Date och från Date till String.

Typparameterkonverteringar

  • Från Object till en typparameter.

  • Från en typparameter till en gränssnittstyp, förutsatt att typparametern inte är begränsad till gränssnittet eller begränsad till en klass som implementerar gränssnittet.

  • Från en gränssnittstyp till en typparameter.

  • Från en typparameter till en härledd typ av en klassbegränsning.

  • Från en typparameter T till allt som en typparameterbegränsning Tx har en begränsad konvertering till.

Typparameterkonverteringar

Typparametrars konverteringar bestäms av eventuella begränsningar. En typparameter T kan alltid konverteras till sig själv, till och från Object, och till och från vilken gränssnittstyp som helst. Observera att om typen T är en värdetyp vid körning, kommer konvertering från T till Object eller en gränssnittstyp att vara en boxningskonvertering och konvertering från Object eller en gränssnittstyp till T kommer att vara en konvertering som avboxas. En typparameter med en klassbegränsning C definierar ytterligare konverteringar från typparametern till C och dess basklasser, och vice versa. En typparameter T med en typparameterbegränsning Tx definierar en konvertering till Tx och allt Tx konverteras till.

En matris vars elementtyp är en typparameter med en gränssnittsbegränsning I har samma samtidiga matriskonverteringar som en matris vars elementtyp är I, förutsatt att typparametern också har en Class eller -klassbegränsning (eftersom endast referensmatriselementtyper kan vara samvarianta). En matris vars elementtyp är en typparameter med en klassbegränsning C har samma samtidiga matriskonverteringar som en matris vars elementtyp är C.

Ovanstående konverteringsregler tillåter inte konverteringar från parametrar av obegränsad typ till icke-gränssnittstyper, vilket kan vara överraskande. Anledningen till detta är att förhindra förvirring om semantiken i sådana omvandlingar. Tänk till exempel på följande deklaration:

Class X(Of T)
    Public Shared Function F(t As T) As Long 
        Return CLng(t)    ' Error, explicit conversion not permitted
    End Function
End Class

Om konverteringen av T till Integer var tillåten kan man enkelt förvänta sig att det X(Of Integer).F(7) skulle returnera 7L. Det skulle det dock inte göra, eftersom numeriska konverteringar endast beaktas när typerna är kända för att vara numeriska vid kompileringstiden. För att semantiken ska bli tydlig måste exemplet ovan i stället skrivas:

Class X(Of T)
    Public Shared Function F(t As T) As Long
        Return CLng(CObj(t))    ' OK, conversions permitted
    End Function
End Class

User-Defined konverteringar

Inbyggda konverteringar är konverteringar som definieras av språket (dvs. anges i den här specifikationen), medan användardefinierade konverteringar definieras genom överbelastning av operatorn CType . När du konverterar mellan typer, om inga inbyggda konverteringar är tillämpliga, kommer användardefinierade konverteringar att övervägas. Om det finns en användardefinierad konvertering som är mest specifik för käll- och måltyperna används den användardefinierade konverteringen. Annars resulterar ett kompileringsfel. Den mest specifika konverteringen är den vars operande är "närmast" källtypen och vars resultattyp är "närmast" måltypen. När du fastställer vilken användardefinierad konvertering som ska användas används den mest specifika breddningskonverteringen. Om ingen utvidgningskonvertering är mest specifik används den mest specifika begränsade konverteringen. Om det inte finns någon mest specifik begränsad konvertering är konverteringen odefinierad och ett kompileringsfel inträffar.

Följande avsnitt beskriver hur de mest specifika konverteringarna bestäms. De använder följande termer:

Om det finns en inbyggd breddningskonvertering från en typ A till en typ B, och om varken A eller B är gränssnitt, omfattas den A av B, och BomfattarA.

Den mest omfattande typen i en uppsättning typer är den typ som omfattar alla andra typer i uppsättningen. Om ingen enskild typ omfattar alla andra typer har uppsättningen ingen mest omfattande typ. I intuitiva termer är den mest omfattande typen den "största" typen i uppsättningen – den typ som var och en av de andra typerna kan konverteras till genom en bredare konvertering.

Den mest omfattande typen i en uppsättning typer är den typ som omfattas av alla andra typer i uppsättningen. Om ingen enskild typ omfattas av alla andra typer har uppsättningen ingen mest omfattande typ. I intuitiva termer är den mest omfattande typen den "minsta" typen i uppsättningen – den typ som kan konverteras till var och en av de andra typerna genom en begränsad konvertering.

När du samlar in kandidatanvändardefinierade konverteringar för en typ T?används de användardefinierade konverteringsoperatorer som definieras av T i stället. Om den typ som konverteras till också är en nullbar värdetyp, lyfts någon av Tde användardefinierade konverteringsoperatorerna som endast omfattar icke-nullbara värdetyper. En konverteringsoperator från T till S lyfts för att vara en konvertering från T? till S? och utvärderas genom att T? konvertera till T, om det behövs, sedan utvärdera den användardefinierade konverteringsoperatorn från T till S och sedan konvertera S till S?, om det behövs. Om värdet som konverteras är Nothingkonverteras dock en hävd konverteringsoperator direkt till ett värde som Nothing skrivs som S?. Till exempel:

Structure S
    ...
End Structure

Structure T
    Public Shared Widening Operator CType(ByVal v As T) As S
        ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim x As T?
        Dim y As S?

        y = x                ' Legal: y is still null
        x = New T()
        y = x                ' Legal: Converts from T to S
    End Sub
End Module

När du löser konverteringar föredras alltid användardefinierade konverteringsoperatorer framför hävda konverteringsoperatorer. Till exempel:

Structure S
    ...
End Structure

Structure T
    Public Shared Widening Operator CType(ByVal v As T) As S
        ...
    End Operator

    Public Shared Widening Operator CType(ByVal v As T?) As S?
        ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim x As T?
        Dim y As S?

        y = x                ' Calls user-defined conversion, not lifted conversion
    End Sub
End Module

Vid körning kan utvärdering av en användardefinierad konvertering omfatta upp till tre steg:

  1. Först konverteras värdet från källtypen till operandtypen med hjälp av en inbyggd konvertering, om det behövs.

  2. Sedan anropas den användardefinierade konverteringen.

  3. Slutligen konverteras resultatet av den användardefinierade konverteringen till måltypen med hjälp av en inbyggd konvertering, om det behövs.

Det är viktigt att observera att utvärderingen av en användardefinierad konvertering aldrig kommer att omfatta mer än en användardefinierad konverteringsoperator.

Mest specifika utvidgningskonvertering

Du kan fastställa den mest specifika användardefinierade breddningskonverteringsoperatorn mellan två typer med hjälp av följande steg:

  1. För det första samlas alla kandidatkonverteringsoperatorer in. Kandidatkonverteringsoperatorerna är alla användardefinierade breddningskonverteringsoperatorer i källtypen och alla användardefinierade breddningskonverteringsoperatorer i måltypen.

  2. Sedan tas alla icke-tillämpliga konverteringsoperatorer bort från uppsättningen. En konverteringsoperator gäller för en källtyp och måltyp om det finns en inbyggd breddningskonverteringsoperator från källtypen till operandtypen och det finns en inbyggd breddningskonverteringsoperator från resultatet av operatorn till måltypen. Om det inte finns några tillämpliga konverteringsoperatorer finns det ingen mest specifik utvidgningskonvertering.

  3. Sedan bestäms den mest specifika källtypen för de tillämpliga konverteringsoperatorerna:

    • Om någon av konverteringsoperatorerna konverterar direkt från källtypen är källtypen den mest specifika källtypen.

    • Annars är den mest specifika källtypen den mest omfattande typen i den kombinerade uppsättningen av källtyper för konverteringsoperatorerna. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen specifik breddningskonvertering.

  4. Sedan bestäms den mest specifika måltypen för de tillämpliga konverteringsoperatorerna:

    • Om någon av konverteringsoperatorerna konverterar direkt till måltypen är måltypen den mest specifika måltypen.

    • Annars är den mest specifika måltypen den mest omfattande typen i den kombinerade uppsättningen av måltyper för konverteringsoperatorerna. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen specifik breddningskonvertering.

  5. Om exakt en konverteringsoperator sedan konverterar från den mest specifika källtypen till den mest specifika måltypen är detta den mest specifika konverteringsoperatorn. Om det finns fler än en sådan operator finns det ingen mest specifik utvidgningskonvertering.

Mest specifik smalningskonvertering

Du kan fastställa den mest specifika användardefinierade konverteringsoperatorn mellan två typer med hjälp av följande steg:

  1. För det första samlas alla kandidatkonverteringsoperatorer in. Kandidatkonverteringsoperatorerna är alla användardefinierade konverteringsoperatorer i källtypen och alla användardefinierade konverteringsoperatorer i måltypen.

  2. Sedan tas alla icke-tillämpliga konverteringsoperatorer bort från uppsättningen. En konverteringsoperator gäller för en källtyp och måltyp om det finns en inbyggd konverteringsoperator från källtypen till operandtypen och det finns en inbyggd konverteringsoperator från resultatet av operatorn till måltypen. Om det inte finns några tillämpliga konverteringsoperatorer finns det ingen mest specifik begränsad konvertering.

  3. Sedan bestäms den mest specifika källtypen för de tillämpliga konverteringsoperatorerna:

    • Om någon av konverteringsoperatorerna konverterar direkt från källtypen är källtypen den mest specifika källtypen.

    • Annars, om någon av konverteringsoperatorerna konverterar från typer som omfattar källtypen, är den mest specifika källtypen den mest omfattande typen i den kombinerade uppsättningen av källtyper för dessa konverteringsoperatorer. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen mest specifik begränsad konvertering.

    • Annars är den mest specifika källtypen den mest omfattande typen i den kombinerade uppsättningen av källtyper för konverteringsoperatorerna. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen mest specifik begränsad konvertering.

  4. Sedan bestäms den mest specifika måltypen för de tillämpliga konverteringsoperatorerna:

    • Om någon av konverteringsoperatorerna konverterar direkt till måltypen är måltypen den mest specifika måltypen.

    • Annars, om någon av konverteringsoperatorerna konverterar till typer som omfattas av måltypen, är den mest specifika måltypen den mest omfattande typen i den kombinerade uppsättningen av källtyper för dessa konverteringsoperatorer. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen mest specifik begränsad konvertering.

    • Annars är den mest specifika måltypen den mest omfattande typen i den kombinerade uppsättningen av måltyper för konverteringsoperatorerna. Om det inte går att hitta någon av de mest omfattande typerna finns det ingen mest specifik begränsad konvertering.

  5. Om exakt en konverteringsoperator sedan konverterar från den mest specifika källtypen till den mest specifika måltypen är detta den mest specifika konverteringsoperatorn. Om det finns fler än en sådan operator finns det ingen mest specifik begränsad konvertering.

Interna konverteringar

Flera av konverteringarna klassificeras som interna konverteringar eftersom de stöds internt av .NET Framework. Dessa konverteringar är sådana som kan optimeras genom användning av DirectCast operatorerna och TryCast konverteringsoperatorerna samt andra särskilda beteenden. Konverteringarna som klassificeras som interna konverteringar är: identitetskonverteringar, standardkonverteringar, referenskonverteringar, matriskonverteringar, värdetypskonverteringar och typparameterkonverteringar.

Dominerande typ

Med tanke på en uppsättning typer är det ofta nödvändigt i situationer som typinferens för att fastställa uppsättningens dominerande typ . Den dominerande typen av en uppsättning typer bestäms genom att först ta bort alla typer som en eller flera andra typer inte har en implicit konvertering till. Om det inte finns några typer kvar i det här läget finns det ingen dominerande typ. Den dominerande typen är då den mest omfattande av de återstående typerna. Om det finns mer än en typ som är mest omfattande finns det ingen dominerande typ.