Sdílet prostřednictvím


Převody v jazyce Visual Basic

Převod je proces změny hodnoty z jednoho typu na jiný. Například hodnotu typu Integer lze převést na hodnotu typu Doublenebo hodnotu typu Derived lze převést na hodnotu typu Base, za předpokladu, že Base a Derived jsou třídy a Derived dědí z Base. Převody nemusí vyžadovat, aby se samotná hodnota změnila (jako v druhém příkladu), nebo mohou vyžadovat významné změny v reprezentaci hodnoty (jako v dřívějším příkladu).

Převody můžou být buď rozšiřující, nebo zúžené. Rozšiřující převod je převod z typu na jiný typ, jehož doména hodnot je alespoň tak velká, pokud není větší, než doména hodnoty původního typu. Rozšiřující převody by nikdy neměly selhat. Zužující převod je převod z typu na jiný typ, jehož doména hodnot je buď menší než doména hodnoty původního typu, nebo dostatečně nesouvisí s tím, že při převodu (například při převodu z Integer naString). Zúžení převodů, které mohou znamenat ztrátu informací, může selhat.

Převod identity (tj. převod typu na sebe) a výchozí převod hodnoty (tj. převod z Nothing) jsou definovány pro všechny typy.

Implicitní a explicitní převody

Převody můžou být implicitní nebo explicitní. Implicitní převody probíhají bez jakékoli speciální syntaxe. Následuje příklad implicitního převodu Integer hodnoty na Long hodnotu:

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

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

Explicitní převody na druhou stranu vyžadují operátory přetypování. Pokus o explicitní převod hodnoty bez operátoru přetypování způsobí chybu v době kompilace. Následující příklad používá explicitní převod k převodu Long hodnoty na Integer hodnotu.

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

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

Sada implicitních převodů závisí na prostředí kompilace a příkazu Option Strict . Pokud se používají striktní sémantika, může implicitně dojít pouze k rozšiřujícím převodům. Pokud se používá permissivní sémantika, může dojít implicitně ke všem rozšiřujícím a zužujícím převodům (jinými slovy ke všem převodům).

Logické převody

I když Boolean není číselný typ, má zužující převody na a z číselných typů, jako by to byl výčtový typ. Literál True se převede na literál 255 pro , 65535 pro ByteUShort, 4294967295 pro UInteger, 18446744073709551615 pro ULong, a na výraz -1 pro SByte, Short, , , IntegerLong, Decimal, Singlea Double. Literál False se převede na literál 0. Nulová číselná hodnota se převede na literál False. Všechny ostatní číselné hodnoty se převedou na literál True.

Existuje zužující převod z logické na řetězec, převod na buď System.Boolean.TrueString nebo System.Boolean.FalseString. Existuje také zužující převod z StringBoolean: pokud byl řetězec roven TrueString nebo FalseString (v aktuální jazykové verzi nerozlišuje malá a velká písmena), použije odpovídající hodnotu; jinak se pokusí analyzovat řetězec jako číselný typ (v šestnáctkovém nebo osmičkovém případě, pokud je to možné, jinak jako float) a použije výše uvedená pravidla; jinak vyvolá System.InvalidCastException.

Číselné převody

Mezi typy Byte, , , UIntegerUShortSByteShortInteger, ULong, , DecimalLongSingle a , a Doublevšechny výčtové typy existují číselné převody. Při převodu se výčtové typy považují za jejich základní typy. Při převodu na výčtový typ není zdrojová hodnota nutná k tomu, aby odpovídala sadě hodnot definovaných v výčtovém typu. Například:

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

Číselné převody se zpracovávají za běhu následujícím způsobem:

  • Pro převod z číselného typu na širší číselný typ se hodnota jednoduše převede na širší typ. Převody z UInteger, , Integer, LongULongnebo do Single nebo DecimalDouble jsou zaokrouhleny na nejbližší Single nebo Double hodnotu. I když tento převod může způsobit ztrátu přesnosti, nikdy nezpůsobí ztrátu velikosti.

  • Při převodu celočíselného typu na jiný celočíselný typ nebo z Single, Doublenebo Decimal na celočíselný typ závisí výsledek na tom, zda je kontrola přetečení celého čísla na:

    Pokud se kontroluje celočíselné přetečení:

    • Pokud je zdrojem celočíselný typ, převod proběhne úspěšně, pokud je zdrojový argument v rozsahu cílového typu. Převod vyvolá System.OverflowException výjimku, pokud je zdrojový argument mimo rozsah cílového typu.

    • Pokud je Singlezdroj , Doublenebo Decimal, je zdroj hodnota zaokrouhleno nahoru nebo dolů na nejbližší celočíselnou hodnotu, a tato integrální hodnota se stane výsledkem převodu. Pokud je zdrojová hodnota stejně blízko ke dvěma celočíselným hodnotám, hodnota se zaokrouhlí na hodnotu, která má sudé číslo v nejméně významné pozici číslice. Pokud je výsledná integrální hodnota mimo rozsah cílového typu, System.OverflowException vyvolá se výjimka.

    Pokud se celočíselné přetečení nekontroluje:

    • Pokud je zdrojem celočíselný typ, převod vždy proběhne úspěšně a jednoduše se skládá z vyřazení nejvýznamnějších bitů zdrojové hodnoty.

    • Pokud je Singlezdroj , Doublenebo Decimal, převod vždy úspěšně a jednoduše se skládá z zaokrouhlení zdrojové hodnoty na nejbližší celočíselnou hodnotu. Pokud je zdrojová hodnota stejně blízko ke dvěma celočíselným hodnotám, hodnota se vždy zaokrouhlí na hodnotu, která má sudé číslo v nejméně významné pozici číslic.

  • Při převodu z Double na SingleDouble se hodnota zaokrouhlí na nejbližší Single hodnotu. Double Pokud je hodnota příliš malá, aby představovala jako , výsledek se změní na kladnou nulu Singlenebo zápornou nulu. Double Pokud je hodnota příliš velká, aby představovala jako , Singlevýsledek se změní na kladné nekonečno nebo záporné nekonečno. Double Pokud je NaNhodnota , výsledek je také NaN.

  • U převodu z Single nebo Double na Decimalje zdrojová hodnota převedena na Decimal reprezentaci a v případě potřeby se zaokrouhlí na nejbližší číslo za 28. desetinnou čárkou. Pokud je zdrojová hodnota příliš malá, aby představovala jako , výsledek se změní na nulu Decimal. Pokud je NaNzdrojová hodnota , nekonečno nebo příliš velké pro reprezentaci jako Decimal, System.OverflowException je vyvolán výjimka.

  • Při převodu z Double na SingleDouble se hodnota zaokrouhlí na nejbližší Single hodnotu. Double Pokud je hodnota příliš malá, aby představovala jako , výsledek se změní na kladnou nulu Singlenebo zápornou nulu. Double Pokud je hodnota příliš velká, aby představovala jako , Singlevýsledek se změní na kladné nekonečno nebo záporné nekonečno. Double Pokud je NaNhodnota , výsledek je také NaN.

Převody odkazů

Odkazové typy mohou být převedeny na základní typ a naopak. Převody ze základního typu na odvozenější typ jsou úspěšné pouze v době běhu, pokud je převedená hodnota null, odvozený typ samotný nebo více odvozený typ.

Typy tříd a rozhraní lze přetypovat do libovolného typu rozhraní a z libovolného typu rozhraní. Převody mezi typem a typem rozhraní jsou úspěšné pouze v době běhu, pokud skutečné typy mají vztah dědičnosti nebo implementace. Vzhledem k tomu, že typ rozhraní bude vždy obsahovat instanci typu odvozeného z Object, typ rozhraní může být také vždy přetypován do a z Object.

Poznámka. Nejedná se o chybu při převodu NotInheritable tříd do a z rozhraní, která neimplementuje, protože třídy představující třídy modelu COM mohou mít implementace rozhraní, které nejsou známy do doby běhu.

Pokud převod odkazu selže za běhu, vyvolá System.InvalidCastException se výjimka.

Převody odchylek odkazů

Obecná rozhraní nebo delegáti mohou mít parametry variantního typu, které umožňují převody mezi kompatibilními variantami typu. Proto při běhu převod z typu třídy nebo typu rozhraní na typ rozhraní, který je varianta kompatibilní s typem rozhraní, který dědí z nebo implementuje, bude úspěšný. Podobně lze typy delegátů přetypovat na a z variant kompatibilních typů delegátů. Například typ delegáta

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

by umožnil převod z F(Of Object, Integer) na F(Of String, Integer). To znamená, že delegát F , který přebírá Object , může být bezpečně používán jako delegát F , který přebírá String. Při vyvolání delegáta bude cílová metoda očekávat objekt a řetězec je objekt.

Obecný delegát nebo typ S(Of S1,...,Sn) rozhraní se říká, že je varianta kompatibilní s obecným rozhraním nebo typem T(Of T1,...,Tn) delegáta, pokud:

  • S a T oba jsou tvořeny ze stejného obecného typu U(Of U1,...,Un).

  • Pro každý parametr Uxtypu:

    • Pokud byl parametr typu deklarován bez rozptylu, Sx pak musí Tx být stejný typ.

    • Pokud byl parametr typu deklarován In , musí existovat rozšiřující identita, výchozí, odkaz, pole nebo převod parametru typu z Sx na Tx.

    • Pokud byl parametr typu deklarován Out , musí existovat rozšiřující identita, výchozí, odkaz, pole nebo převod parametru typu z Tx na Sx.

Při převodu z třídy na obecné rozhraní s parametry variant typu, pokud třída implementuje více než jedno rozhraní kompatibilní s variantou, převod je nejednoznačný, pokud neexistuje převod jiné varianty. Například:

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

Převody anonymních delegátů

Pokud je výraz klasifikovaný jako metoda lambda přetříděný jako hodnota v kontextu, kde neexistuje žádný cílový typ (například Dim x = Function(a As Integer, b As Integer) a + b) nebo pokud cílový typ není delegovaným typem, je typ výsledného výrazu anonymní typ delegáta ekvivalentní podpisu metody lambda. Tento typ anonymního delegáta má převod na jakýkoli kompatibilní typ delegáta: kompatibilní typ delegáta je jakýkoli typ delegáta, který lze vytvořit pomocí výrazu pro vytvoření delegáta s metodou anonymního typu Invoke delegáta jako parametr. Například:

' 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

Všimněte si, že typy System.Delegate a System.MulticastDelegate nejsou samy o sobě považovány za typy delegátů (i když se z nich dědí všechny typy delegátů). Všimněte si také, že převod z anonymního typu delegáta na kompatibilní typ delegáta není převod odkazu.

Převody polí

Kromě převodů, které jsou definovány na polích na základě skutečnosti, že se jedná o odkazové typy, existuje několik speciálních převodů pro pole.

Pro všechny dva typy A a B, pokud jsou oba odkazové typy nebo parametry typu, které nejsou známé jako hodnotové typy, a pokud A má odkaz, pole nebo převod parametrů typu na B, převod existuje z pole typu A na matici typu B se stejným pořadím. Tato relace se označuje jako kovariance pole. Maticová kovariance zejména znamená, že prvek pole, jehož typ prvku je B ve skutečnosti prvkem pole, jehož typ prvku je A, za předpokladu, že oba A a B jsou odkazové typy a které B mají převod odkazu nebo pole převodu na A. V následujícím příkladu druhé vyvolání F příčin vyvolání výjimky, protože skutečný typ b prvku je String, nikoli ObjectSystem.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

Z důvodu kovariance pole pole obsahují přiřazení prvků referenčního typu kontrolu za běhu, která zajišťuje, že hodnota přiřazená k prvku pole je ve skutečnosti povolený 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

V tomto příkladu přiřazení metody array(i)Fill implicitně zahrnuje kontrolu za běhu, která zajišťuje, že objekt odkazovaný proměnnou value je buď Nothing nebo instance typu, který je kompatibilní se skutečným typem prvku pole array. V metodě Mainjsou první dvě vyvolání metody Fill úspěšné, ale třetí vyvolání způsobí System.ArrayTypeMismatchException výjimku při spuštění prvního přiřazení .array(i) K výjimce dochází, protože Integer nelze uložit do String pole.

Pokud jeden z typů prvků pole je parametr typu, jehož typ se ukáže jako typ hodnoty za běhu, System.InvalidCastException vyvolá se výjimka. Například:

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

Převody existují také mezi polem výčtového typu a polem podkladového typu výčtového typu nebo polem jiného výčtového typu se stejným základním typem za předpokladu, že pole mají stejné pořadí.

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

V tomto příkladu je pole Color převedeno na a z pole základního Bytetypu . Color Převod na pole Integervšak bude chybou, protože Integer není základním typem Color.

Pole typu A() rank-1 má také převod pole na typy IList(Of B)rozhraní kolekce , IReadOnlyList(Of B)a IEnumerable(Of B)ICollection(Of B)IReadOnlyCollection(Of B) nalezeny v System.Collections.Generic, pokud je splněna jedna z následujících hodnot:

  • A a B jsou referenčními typy nebo parametry typu, které nejsou známy jako hodnotové typy; a A mají rozšiřující odkaz, matici nebo převod parametrů typu na B; nebo
  • A a B jsou oba typy výčtu stejného základního typu; nebo
  • jeden z A a B je výčtovým typem a druhý je jeho podkladovým typem.

Jakékoli pole typu A s libovolným pořadím má také převod pole na typy ne generických rozhraní IListkolekce a ICollectionIEnumerable nachází se v System.Collections.

Je možné iterovat přes výsledná rozhraní pomocí For Each, nebo prostřednictvím vyvolání GetEnumerator metod přímo. V případě matic rank-1 převedené obecné nebo ne generické formy IList nebo ICollection, je také možné získat prvky podle indexu. V případě polí rank-1 převedených na obecné nebo ne generické formy IListje také možné nastavit prvky indexem, s výhradou stejných kontrol kovariance pole modulu runtime, jak je popsáno výše. Chování všech ostatních metod rozhraní není definováno specifikací jazyka VB; je až do základního modulu runtime.

Převody typů hodnot

Hodnotu typu hodnoty lze převést na jeden z jeho základních referenčních typů nebo na typ rozhraní, který implementuje prostřednictvím procesu nazývaného boxing. Pokud je hodnota typu hodnoty v rámečku, hodnota se zkopíruje z umístění, kde se nachází do haldy rozhraní .NET Framework. Odkaz na toto umístění v haldě se pak vrátí a může být uložen v proměnné typu odkazu. Tento odkaz se také označuje jako boxovaná instance typu hodnoty. Boxed instance má stejnou sémantiku jako typ odkazu místo typu hodnoty.

Boxed value types can be converted back to their original value type through a process called unboxing. Pokud je typ hodnoty v rámečku rozbalený, hodnota se zkopíruje z haldy do umístění proměnné. Od tohoto okamžiku se chová jako typ hodnoty. Při rozbalení typu hodnoty musí být hodnota null nebo instance typu hodnoty. System.InvalidCastException V opačném případě je vyvolán výjimka. Pokud je hodnota instancí výčtového typu, může být tato hodnota také rozbalována do výčtového typu podkladového typu nebo jiného výčtového typu, který má stejný základní typ. Hodnota null je považována za literál Nothing.

Pro podporu typů hodnot s možnou hodnotou null je typ System.Nullable(Of T) hodnoty zpracován speciálně při balení a rozbalení. Boxing a value of type Nullable(Of T) results in a boxed value of type T if the value's HasValue property is True or a value of Nothing if the value's HasValue property is False. Unboxing a value of type T to Nullable(Of T) results in an instance of Nullable(Of T) jehož Value vlastnost is the boxed value and jehož HasValue vlastnost is True. Hodnotu Nothing lze rozbalit Nullable(Of T) pro libovolnou T hodnotu a výsledkem je hodnota, jejíž HasValue vlastnost je False. Vzhledem k tomu, že se typy hodnot v rámečku chovají jako odkazové typy, je možné vytvořit více odkazů na stejnou hodnotu. Pro primitivní typy a výčtové typy je to irelevantní, protože instance těchto typů jsou neměnné. To znamená, že není možné upravit krabicovou instanci těchto typů, takže není možné sledovat skutečnost, že existuje více odkazů na stejnou hodnotu.

Naopak struktury mohou být proměnlivé, pokud jsou proměnné instance přístupné nebo pokud jeho metody nebo vlastnosti upravují proměnné instance. Pokud se k úpravě struktury používá jeden odkaz na krabicovou strukturu, všechny odkazy na krabicovou strukturu uvidí změnu. Vzhledem k tomu, že tento výsledek může být neočekávaný, když se hodnota zadává tak, jak Object je zkopírována z jednoho umístění do jiného typu hodnot v rámečku, automaticky se naklonuje na haldě místo pouhého zkopírování odkazů. Například:

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

Výstupem programu je:

Values: 0, 123
Refs: 123, 123

Přiřazení k poli místní proměnné val2 nemá vliv na pole místní proměnnéval1, protože při přiřazení val2pole Struct1 byla provedena kopie hodnoty. Naproti tomu přiřazení ref2.Value = 123 ovlivňuje objekt, který a ref1ref2 odkazy.

Poznámka. Kopírování struktury není provedeno u krabicových struktur zadaných jako System.ValueType proto, že není možné opožděně svázat .System.ValueType

Existuje jedna výjimka pravidla, které se při přiřazení zkopírují typy hodnot v rámečku. Pokud je odkaz typu hodnoty v rámečku uložen v jiném typu, vnitřní odkaz nebude zkopírován. Například:

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

Výstupem programu je:

Values: 123, 123

Důvodem je to, že vnitřní boxovaná hodnota není zkopírována při kopírování hodnoty. val1.Value Proto obě a val2.Value mají odkaz na stejný typ hodnoty v rámečku.

Poznámka. Skutečnost, že se nekopírují vnitřní typy hodnot, je omezení systému typů .NET – aby se zajistilo, že se všechny vnitřní typy hodnot v rámečku zkopírovaly vždy, když byla zkopírovaná hodnota typu Object , byla by zakázána nákladná.

Jak bylo popsáno dříve, dají se typy hodnot v rámečku rozbalit pouze do původního typu. Rámeček primitivní typy, nicméně, jsou zpracovávány speciálně při psaní jako Object. Lze je převést na jakýkoli jiný primitivní typ, na který mají převod. Například:

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

Integer 5 Byte Za normálníchokolnostch Vzhledem k tomu, že Integer a Byte jsou primitivní typy a mají převod, převod je povolen.

Je důležité si uvědomit, že převod typu hodnoty na rozhraní se liší od obecného argumentu omezeného na rozhraní. Při přístupu k členům rozhraní u parametru omezeného typu (nebo volání metod) Objectse boxing neprojeví stejně, jako když je typ hodnoty převeden na rozhraní a je přístupný člen rozhraní. Předpokládejme například, že rozhraní ICounter obsahuje metodu Increment , kterou lze použít k úpravě hodnoty. Pokud ICounter se používá jako omezení, je volána implementace Increment metody s odkazem na proměnnou, která Increment byla volána, nikoli boxed kopie:

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

První volání Increment modifikuje hodnotu v proměnné x. Toto není ekvivalentem druhého volání Increment, které upraví hodnotu v zabalené kopii x. Výstupem programu je tedy:

0
1
1

Převody typů hodnot s možnou hodnotou null

Typ T hodnoty lze převést na a z verze typu s možnou hodnotou null. T? Převod z T? na T vyvolá System.InvalidOperationException výjimku, pokud je hodnota převedena Nothing. T? Má také převod na typS, pokud T má vnitřní převod na S. A pokud S je typ hodnoty, existují následující vnitřní převody mezi T? a S?:

  • Převod stejné klasifikace (zúžení nebo rozšíření) od T? do S?.

  • Převod stejné klasifikace (zúžení nebo rozšíření) od T do S?.

  • Zužující převod z S? na T.

Například vnitřní rozšiřující převod existuje z Integer? toho Long? důvodu, že vnitřní rozšiřující převod existuje zInteger:Long

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

Při převodu z T? na S?, pokud je Nothinghodnota T? , pak hodnota S? bude Nothing. Při převodu z S? nebo TT? na S, pokud hodnota T? nebo S? je Nothing, System.InvalidCastException bude vyvolán výjimka.

Vzhledem k chování základního typu System.Nullable(Of T), pokud je typ T? hodnoty null pole, výsledek je krabicová hodnota typu T, nikoli boxed hodnota typu T?. A naopak při rozbalení na typ T?hodnoty s možnou hodnotou null bude hodnota zabalena System.Nullable(Of T)a Nothing bude rozbalena na hodnotu null typu T?. Například:

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

Vedlejším účinkem tohoto chování je, že se zdá, že typ T? hodnoty null implementuje všechna rozhraní T, protože převod typu hodnoty na rozhraní vyžaduje typ box. Výsledkem je převod na všechna rozhraní, T? na která T se konvertibilní. Je však důležité poznamenat, že typ T? hodnoty null ve skutečnosti neimplementuje rozhraní T pro účely obecné kontroly omezení nebo reflexe. Například:

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

Převody řetězců

Převod Char na String výsledky v řetězci, jehož prvním znakem je hodnota znaku. Převod String na Char výsledky ve znaku, jehož hodnota je prvním znakem řetězce. Převod pole Char na String výsledky v řetězci, jehož znaky jsou prvky pole. Převod String na pole výsledků v matici Char znaků, jejichž prvky jsou znaky řetězce.

Přesné převody mezi a , , ByteUIntegerShortSByteIntegerUShortDecimalLongULong, Single, Double, Date, a naopak, jsou nad rámec této specifikace a jsou implementace závislá s výjimkou jednoho detailu.BooleanString Převody řetězců vždy berou v úvahu aktuální jazykovou verzi prostředí za běhu. Proto je nutné je provést za běhu.

Rozšiřující převody

Rozšiřující převody nikdy nepřeteče, ale mohou znamenat ztrátu přesnosti. Následující převody jsou rozšiřující převody:

Převody identit nebo výchozích hodnot

  • Od typu k sobě.

  • Z anonymního typu delegáta vygenerovaného pro přetřídění metody lambda na jakýkoli typ delegáta s identickým podpisem.

  • Z literálu Nothing na typ.

Číselné převody

  • Od Byte do , UShort, , Short, , UInteger, IntegerULongLongDecimalnebo .SingleDouble

  • Od SByte po Short, Integer, Long, Decimal, Singlenebo Double.

  • Od UShort po UInteger, Integer, ULong, Long, Decimal, Singlenebo Double.

  • Od Short do Integer, Long, DecimalSingle nebo Double.

  • Od UInteger po ULong, Long, Decimal, Singlenebo Double.

  • Od Integer do Long, DecimalSingle nebo Double.

  • Od ULong po Decimal, Singlenebo Double.

  • Od Long do Decimal, Single nebo Double.

  • Od Decimal do Single nebo Double.

  • Od Single do Double.

  • Z literálu 0 na výčtový typ. (Poznámka: Převod z 0 libovolného výčtového typu se rozšiřuje, aby se zjednodušily testovací příznaky. Pokud Values je například výčtový typ s hodnotou One, můžete otestovat proměnnou v typu Values tím, že řeknete (v And Values.One) = 0.)

  • Z výčtového typu na základní číselný typ nebo na číselný typ, na který má základní číselný typ rozšiřující převod.

  • Z konstantního výrazu typu ULong, , UIntegerUShortIntegerShortLongByte, nebo SByte užšího typu, za předpokladu, že hodnota konstantního výrazu je v rozsahu cílového typu. (Poznámka: Převody z UInteger nebo Integer na Single, ULong nebo na Single nebo DoubleLong na nebo DecimalSingleDouble mohou způsobit ztrátu přesnosti, ale nikdy nezpůsobí ztrátu velikosti. Ostatní rozšiřující číselné převody nikdy neztratí žádné informace.)

Převody odkazů

  • Z typu odkazu na základní typ.

  • Z referenčního typu na typ rozhraní za předpokladu, že typ implementuje rozhraní nebo variantně kompatibilní rozhraní.

  • Z typu rozhraní do Object.

  • Typ rozhraní až po typ rozhraní kompatibilní s variantou.

  • Z typu delegáta na typ delegáta kompatibilního s variantou. (Poznámka: Tato pravidla implikují mnoho dalších převodů odkazů. Anonymní delegáti jsou například odkazové typy, které dědí z System.MulticastDelegate; typy polí jsou odkazové typy, které dědí z System.Array; anonymní typy jsou odkazové typy, které dědí z System.Object.)

Převody anonymních delegátů

  • Z anonymního typu delegáta vygenerovaného pro přetřídění metody lambda na jakýkoli širší typ delegáta.

Převody polí

  • Z typu pole s typem SSe prvku na typ T pole s typem Teelementu , za předpokladu, že jsou splněny všechny následující podmínky:

    • S a T liší se pouze v typu prvku.

    • Oba Se a Te jsou odkazové typy nebo jsou parametry typu známé jako odkazový typ.

    • Rozšiřující odkaz, pole nebo převod parametru typu existuje z Se na Te.

  • Z typu S pole s výčtovým typem Se elementu na typ T pole s typem Teelementu jsou splněny všechny následující podmínky:

    • S a T liší se pouze v typu prvku.

    • Teje základní typ .Se

  • Z typu S pole pořadí 1 s výčtovým typem Seprvku , do System.Collections.Generic.IList(Of Te), IReadOnlyList(Of Te), ICollection(Of Te), IReadOnlyCollection(Of Te), a IEnumerable(Of Te), za předpokladu, že platí jedna z následujících hodnot:

    • Oba Se a Te jsou odkazové typy nebo jsou parametry typu známé jako odkazový typ, a rozšiřující odkaz, pole nebo převod parametru typu existuje z SeTe; nebo

    • Te je základní typ Se; nebo

    • Te je shodná s Se

Převody typu hodnoty

  • Ze typu hodnoty do základního typu.

  • Z typu hodnoty na typ rozhraní, který typ implementuje.

Převody typů hodnot s možnou hodnotou null

  • Z typu T na typ T?.

  • Z typu T? na typ S?, kde existuje rozšiřující převod z typu T na typ S.

  • Z typu T na typ S?, kde existuje rozšiřující převod z typu T na typ S.

  • Z typu T? na typ rozhraní, který typ T implementuje.

Převody řetězců

  • Od Char do String.

  • Od Char() do String.

Převody parametrů typu

  • Z parametru typu do Object.

  • Z parametru typu na omezení typu rozhraní nebo jakékoli varianty rozhraní kompatibilní s omezením typu rozhraní.

  • Z parametru typu na rozhraní implementované omezením třídy.

  • Z parametru typu na variantu rozhraní kompatibilní s rozhraním implementovaným omezením třídy.

  • Z parametru typu do omezení třídy nebo základního typu omezení třídy.

  • Z parametru T typu na omezení Txparametru typu nebo cokoli Tx má rozšiřující převod na.

Zúžení konverze

Zužující převody jsou převody, které nelze prokázat vždy úspěšně, převody, které jsou známé, že pravděpodobně ztratí informace, a převody napříč doménami typů dostatečně odlišné, aby si zaslouží zúžení notace. Následující převody jsou klasifikovány jako zužující převody:

Logické převody

  • Od , , , Boolean, , Byte, SByte, UShort, ShortUInteger, Integer, ULong, nebo Long. DecimalSingleDouble

  • Od Byte, SByte, , UShort, Short, , UInteger, Integer, DecimalULongSingleLongnebo Double do .Boolean

Číselné převody

  • Od Byte do SByte.

  • Od SByte po Byte, UShort, UIntegernebo ULong.

  • Od UShort po Byte, SBytenebo Short.

  • Od Short po Byte, SByte, UShort, UIntegernebo ULong.

  • Od UInteger po Byte, SByte, UShort, Shortnebo Integer.

  • Od Integer po Byte, SByte, UShort, Short, UIntegernebo ULong.

  • Od ULong po Byte, SByte, UShort, Short, UInteger, Integernebo Long.

  • Od Long po Byte, SByte, UShort, Short, UInteger, Integernebo ULong.

  • Od Decimal po Byte, SByte, UShort, Short, UInteger, Integer, ULongnebo Long.

  • Od Single do , Byte, , SByte, , UShort, ShortUIntegerIntegerULongnebo .LongDecimal

  • Od Double do Byte, SByte, , UShort, , Short, UInteger, IntegerULongLongDecimal, , nebo .Single

  • Z číselného typu na výčtový typ.

  • Z výčtového typu na číselný typ má jeho základní číselný typ zužující převod na.

  • Z výčtového typu do jiného výčtového typu.

Převody odkazů

  • Z typu odkazu na odvozenější typ.

  • Z typu třídy na typ rozhraní za předpokladu, že typ třídy neimplementuje typ rozhraní ani variantu typu rozhraní kompatibilní s ním.

  • Z typu rozhraní na typ třídy.

  • Z typu rozhraní na jiný typ rozhraní neexistuje žádný vztah dědičnosti mezi těmito dvěma typy a za předpokladu, že nejsou kompatibilní s variantou.

Převody anonymních delegátů

  • Z anonymního typu delegáta vygenerovaného pro přetřídění metody lambda na jakýkoli užší typ delegáta.

Převody polí

  • Z typu pole s typem SSeelementu až po typ T pole s typem Teprvku za předpokladu, že platí všechny následující skutečnosti:

    • S a T liší se pouze v typu prvku.
    • Oba Se a Te jsou odkazové typy nebo jsou parametry typu, které nejsou známé jako typy hodnot.
    • Zužující odkaz, pole nebo převod parametru typu existuje z Se do Te.
  • Z typu pole s typem SSe elementu na typ T pole s výčtovým typem Teelementu jsou splněny všechny následující skutečnosti:

    • S a T liší se pouze v typu prvku.
    • Se je základní typ , Te nebo jsou oba různé výčtové typy, které sdílejí stejný základní typ.
  • Z typu S pole pořadí 1 s výčtovým typem Seprvku , do IList(Of Te), IReadOnlyList(Of Te), ICollection(Of Te)IReadOnlyCollection(Of Te) a IEnumerable(Of Te), za předpokladu, že platí jedna z následujících hodnot:

    • Oba Se a Te jsou odkazové typy nebo jsou parametry typu známé jako odkazový typ, a zužující odkaz, pole nebo převod parametrů typu existuje z SeTe; nebo
    • Se je základní typ , Tenebo jsou oba různé výčtové typy, které sdílejí stejný základní typ.

Převody typů hodnot

  • Z typu odkazu na odvozenější typ hodnoty.

  • Z typu rozhraní na typ hodnoty za předpokladu, že typ hodnoty implementuje typ rozhraní.

Převody typů hodnot s možnou hodnotou null

  • Z typu T? na typ T.

  • Z typu T? na typ S?, kde existuje zužující převod z typu T na typ S.

  • Z typu T na typ S?, kde existuje zužující převod z typu T na typ S.

  • Z typu S? na typ T, kde existuje převod z typu S na typ T.

Převody řetězců

  • Od String do Char.

  • Od String do Char().

  • Od String do Boolean a z Boolean do String.

  • Převody mezi String a Byte, , UShortSByte, ShortLongUIntegerULongDecimalInteger, , Singlenebo .Double

  • Od String do Date a z Date do String.

Převody parametrů typu

  • Od Object parametru typu.

  • Z parametru typu na typ rozhraní za předpokladu, že parametr typu není omezen na toto rozhraní nebo omezen na třídu, která implementuje toto rozhraní.

  • Z typu rozhraní na parametr typu.

  • Z parametru typu na odvozený typ omezení třídy.

  • Z parametru T typu na cokoli, na co má omezení Tx parametru typu zužující převod na.

Převody parametrů typu

Převody parametrů typu jsou určeny omezeními, pokud existují, na ně. Parametr T typu lze vždy převést na sebe, na a z a do Objecta z libovolného typu rozhraní. Všimněte si, že pokud je typ T hodnoty typu za běhu, převodem z T typu do Object nebo typu rozhraní bude převod boxingu a převodem z Object nebo typu rozhraní na T typ rozbalení. Parametr typu s omezením C třídy definuje další převody z parametru typu na C základní třídy a naopak. Parametr T typu s omezením Tx parametru typu definuje převod a Tx cokoli Tx se převede na.

Matice, jejíž typ prvku je parametr typu s omezením I rozhraní má stejné kovariantní maticové převody jako pole, jehož typ prvku je I, za předpokladu, že parametr typu má Class také omezení třídy (protože pouze odkazové typy prvků pole mohou být kovariantní). Pole, jehož typ prvku je parametr typu s omezením C třídy má stejné kovariantní převody pole jako pole, jehož typ prvku je C.

Výše uvedená pravidla převodů neumožňují převody z nekonstruovaných parametrů typu na jiné typy než rozhraní, což může být překvapivý. Důvodem je zabránit nejasnostem ohledně sémantiky těchto převodů. Představte si například následující deklaraci:

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

Pokud by byl převod T na Integer povolení povolen, jeden by mohl snadno očekávat, že X(Of Integer).F(7) by se vrátila 7L. To by však nebylo, protože číselné převody jsou považovány pouze za typy, které jsou známé jako číselné v době kompilace. Aby bylo možné sémantiku smazat, musí být místo toho napsán výše uvedený příklad:

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

převody User-Defined

Vnitřní převody jsou převody definované jazykem (tj. uvedeným v této specifikaci), zatímco uživatelem definované převody jsou definovány přetížením operátoru CType . Pokud se při převodu mezi typy nepoužijí žádné vnitřní převody, budou se brát v úvahu uživatelsky definované převody. Pokud existuje uživatelsky definovaný převod, který je pro zdrojové a cílové typy nejvýraznější , použije se převod definovaný uživatelem. V opačném případě dojde k chybě kompilace. Nejvýraznější převod je ten, jehož operand je "nejblíže" ke zdrojovému typu a jehož typ výsledku je "nejblíže" cílovému typu. Při určování, který uživatelem definovaný převod se má použít, se použije nejvýraznější rozšiřující převod; pokud není rozšiřující převod nejpřesnější, použije se nejvýraznější zužující převod. Pokud neexistuje nejpřesnější zužující převod, převod není definován a dojde k chybě v době kompilace.

V následujících částech se dozvíte, jak se určují nejvýraznější převody. Používají následující termíny:

Pokud vnitřní rozšiřující převod existuje z typu A na typ B, a pokud ani AB nejsou rozhraní, pak A je zahrnutyBa BzahrnujeA.

Nejvíce zahrnující typ v sadě typů je jeden typ, který zahrnuje všechny ostatní typy v sadě. Pokud žádný jeden typ nezahrnuje všechny ostatní typy, sada nemá nejvíce zahrnující typ. Nejobsáhlejší typ je v sadě nejobsáhlejším typem – jedním typem, na který lze jednotlivé typy převést rozšiřujícím převodem.

Nejobsáhodnější typ v sadě typů je jeden typ, který je zahrnut všemi ostatními typy v sadě. Pokud žádný jeden typ nezahrne všechny ostatní typy, sada neobsahuje nejobsáženější typ. Nejobsáhlejším typem je v sadě nejobsáhlejší typ – jeden typ, který lze převést na každý z ostatních typů pomocí zužujícího převodu.

Při shromažďování převodů definovaných kandidátem pro typ T?se místo toho použijí operátory převodu definované uživatelem T . Pokud je typ převedený také na typ hodnoty null, pak se zvedne kterýkoli z Tuživatelsky definovaných převodních operátorů, které zahrnují pouze typy hodnot s možnou hodnotou null. Operátor převodu z T do S je zvednut, aby byl převod z T? do S? a je vyhodnocen převodem T? na T, v případě potřeby, vyhodnocením uživatelem definovaného převodního operátoru z T do S a následným převodem S na S?, v případě potřeby. Pokud je Nothingvšak převedena hodnota, operátor zdviženého převodu převede přímo na hodnotu typu Nothing jako S?. Například:

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

Při překladupřevodch Například:

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

Vyhodnocení uživatelem definovaného převodu může v době běhu zahrnovat až tři kroky:

  1. Nejprve se hodnota převede ze zdrojového typu na typ operandu pomocí vnitřního převodu, pokud je to nutné.

  2. Pak se vyvolá převod definovaný uživatelem.

  3. Nakonec se výsledek uživatelem definovaného převodu převede na cílový typ pomocí vnitřního převodu v případě potřeby.

Je důležité si uvědomit, že vyhodnocení uživatelem definovaného převodu nikdy nebude zahrnovat více než jeden uživatelem definovaný operátor převodu.

Nejvýraznější rozšiřující převod

Určení nejkonverzního operátoru rozšiřujícího převodu definovaného uživatelem mezi dvěma typy se provádí pomocí následujících kroků:

  1. Nejprve se shromažďují všechny operátory převodu kandidáta. Operátory převodu kandidáta jsou všechny uživatelem definované rozšiřující konverzní operátory ve zdrojovém typu a všechny uživatelem definované rozšiřující operátory převodu v cílovém typu.

  2. Potom se ze sady odeberou všechny nepoužitelné operátory převodu. Operátor převodu se vztahuje na typ zdroje a cílový typ, pokud existuje vnitřní rozšiřující operátor převodu ze zdrojového typu na typ operandu a existuje vnitřní rozšiřující operátor z výsledku operátoru na cílový typ. Pokud neexistují žádné použitelné operátory převodu, neexistuje žádný nejvýraznější rozšiřující převod.

  3. Pak se určí nejvýraznější typ zdroje příslušných operátorů převodu:

    • Pokud některý z operátorů převodu převede přímo ze zdrojového typu, je typ zdroje nejvýraznějším typem zdroje.

    • V opačném případě je nejvýraznější typ zdroje v kombinované sadě zdrojových typů převodních operátorů. Pokud nelze nalézt žádný nejzahrnující typ, neexistuje žádný nejvýraznější rozšiřující převod.

  4. Pak se určí nejvýraznější cílový typ příslušných operátorů převodu:

    • Pokud některý z operátorů převodu převede přímo na cílový typ, pak cílový typ je nejvýraznější cílový typ.

    • V opačném případě je nejvýraznějším cílovým typem typ v kombinované sadě cílových typů konverzních operátorů. Pokud nelze najít nejobsahující typ, neexistuje žádný nejvýraznější rozšiřující převod.

  5. Pokud přesně jeden operátor převodu převede z nejvíce konkrétního typu zdroje na nej specifickou cílovou typ, jedná se o nejvýraznější operátor převodu. Pokud existuje více než jeden takový operátor, neexistuje žádný nejvýraznější rozšiřující převod.

Nejpřesnější zužující převod

Určení nejpřesnějšího zúžení operátoru převodu definovaného uživatelem mezi dvěma typy se provádí pomocí následujících kroků:

  1. Nejprve se shromažďují všechny operátory převodu kandidáta. Operátory převodu kandidáta jsou všechny uživatelem definované konverzní operátory ve zdrojovém typu a všechny uživatelem definované operátory převodu v cílovém typu.

  2. Potom se ze sady odeberou všechny nepoužitelné operátory převodu. Operátor převodu se vztahuje na typ zdroje a cílový typ, pokud existuje vnitřní převodní operátor ze zdrojového typu na typ operandu a existuje vnitřní převodní operátor z výsledku operátoru na cílový typ. Pokud neexistují žádné použitelné operátory převodu, neexistuje žádný nejpřesnější zužující převod.

  3. Pak se určí nejvýraznější typ zdroje příslušných operátorů převodu:

    • Pokud některý z operátorů převodu převede přímo ze zdrojového typu, je typ zdroje nejvýraznějším typem zdroje.

    • V opačném případě, pokud některý z operátorů převodu převádí z typů, které zahrnují zdrojový typ, je nejvýraznější typ zdroje v kombinované sadě zdrojových typů těchto převodních operátorů. Pokud nelze najít nejobsáhlější typ, neexistuje žádný nejpřesnější zužující převod.

    • V opačném případě je nejvýraznější typ zdroje v kombinované sadě zdrojových typů konverzních operátorů. Pokud nelze najít nejobsahující typ, neexistuje žádný nejpřesnější zužující převod.

  4. Pak se určí nejvýraznější cílový typ příslušných operátorů převodu:

    • Pokud některý z operátorů převodu převede přímo na cílový typ, pak cílový typ je nejvýraznější cílový typ.

    • V opačném případě, pokud některý z operátorů převodu převede na typy, které jsou zahrnuty cílovým typem, je nejvýraznější cílový typ v kombinované sadě zdrojových typů těchto převodních operátorů. Pokud nelze najít nejobsahující typ, neexistuje žádný nejpřesnější zužující převod.

    • V opačném případě je nejvýraznější cílový typ v kombinované sadě cílových typů operátorů převodu. Pokud nelze najít nejobsáhlější typ, neexistuje žádný nejpřesnější zužující převod.

  5. Pokud přesně jeden operátor převodu převede z nejvíce konkrétního typu zdroje na nej specifickou cílovou typ, jedná se o nejvýraznější operátor převodu. Pokud existuje více než jeden takový operátor, neexistuje žádný nejpřesnější zužující převod.

Nativní převody

Několik převodů se klasifikuje jako nativní převody , protože jsou nativně podporovány rozhraním .NET Framework. Tyto převody jsou ty, které je možné optimalizovat pomocí operátorů převodu DirectCast a TryCast dalších speciálních chování. Převody klasifikované jako nativní převody jsou: převody identit, výchozí převody, referenční převody, převody polí, převody typů hodnot a převody parametrů typu.

Dominantní typ

Vzhledem k sadě typů je často nutné v situacích, jako je odvození typu určit dominantní typ sady. Dominantní typ sady typů je určen nejprve odebráním všech typů, na které jeden nebo více jiných typů nemá implicitní převod. Pokud v tomto okamžiku neexistují žádné typy, neexistuje žádný dominantní typ. Dominantní typ je pak nejvíce zahrnující zbývající typy. Pokud je více typů, které jsou nejvíce zahrnuty, pak neexistuje žádný dominantní typ.