Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
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 doSingleneboDecimalDoublejsou zaokrouhleny na nejbližšíSingleneboDoublehodnotu. 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,DoubleneboDecimalna 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.OverflowExceptionvýjimku, pokud je zdrojový argument mimo rozsah cílového typu.Pokud je
Singlezdroj ,DoubleneboDecimal, 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.OverflowExceptionvyvolá 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 ,DoubleneboDecimal, 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
DoublenaSingleDoublese hodnota zaokrouhlí na nejbližšíSinglehodnotu.DoublePokud je hodnota příliš malá, aby představovala jako , výsledek se změní na kladnou nuluSinglenebo zápornou nulu.DoublePokud je hodnota příliš velká, aby představovala jako ,Singlevýsledek se změní na kladné nekonečno nebo záporné nekonečno.DoublePokud jeNaNhodnota , výsledek je takéNaN.U převodu z
SingleneboDoublenaDecimalje zdrojová hodnota převedena naDecimalreprezentaci 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 nuluDecimal. Pokud jeNaNzdrojová hodnota , nekonečno nebo příliš velké pro reprezentaci jakoDecimal,System.OverflowExceptionje vyvolán výjimka.Při převodu z
DoublenaSingleDoublese hodnota zaokrouhlí na nejbližšíSinglehodnotu.DoublePokud je hodnota příliš malá, aby představovala jako , výsledek se změní na kladnou nuluSinglenebo zápornou nulu.DoublePokud je hodnota příliš velká, aby představovala jako ,Singlevýsledek se změní na kladné nekonečno nebo záporné nekonečno.DoublePokud jeNaNhodnota , 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:
SaToba jsou tvořeny ze stejného obecného typuU(Of U1,...,Un).Pro každý parametr
Uxtypu:Pokud byl parametr typu deklarován bez rozptylu,
Sxpak musíTxbý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 zSxnaTx.Pokud byl parametr typu deklarován
Out, musí existovat rozšiřující identita, výchozí, odkaz, pole nebo převod parametru typu zTxnaSx.
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:
-
AaBjsou referenčními typy nebo parametry typu, které nejsou známy jako hodnotové typy; aAmají rozšiřující odkaz, matici nebo převod parametrů typu naB; nebo -
AaBjsou oba typy výčtu stejného základního typu; nebo - jeden z
AaBje 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?doS?.Převod stejné klasifikace (zúžení nebo rozšíření) od
TdoS?.Zužující převod z
S?naT.
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
Nothingna typ.
Číselné převody
Od
Bytedo ,UShort, ,Short, ,UInteger,IntegerULongLongDecimalnebo .SingleDoubleOd
SBytepoShort,Integer,Long,Decimal,SingleneboDouble.Od
UShortpoUInteger,Integer,ULong,Long,Decimal,SingleneboDouble.Od
ShortdoInteger,Long,DecimalSingleneboDouble.Od
UIntegerpoULong,Long,Decimal,SingleneboDouble.Od
IntegerdoLong,DecimalSingleneboDouble.Od
ULongpoDecimal,SingleneboDouble.Od
LongdoDecimal,SingleneboDouble.Od
DecimaldoSingleneboDouble.Od
SingledoDouble.Z literálu
0na výčtový typ. (Poznámka: Převod z0libovolného výčtového typu se rozšiřuje, aby se zjednodušily testovací příznaky. PokudValuesje například výčtový typ s hodnotouOne, můžete otestovat proměnnouvtypuValuestí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, neboSByteužšího typu, za předpokladu, že hodnota konstantního výrazu je v rozsahu cílového typu. (Poznámka: Převody zUIntegerneboIntegernaSingle,ULongnebo naSingleneboDoubleLongna neboDecimalSingleDoublemohou 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í zSystem.Array; anonymní typy jsou odkazové typy, které dědí zSystem.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
SSeprvku na typTpole s typemTeelementu , za předpokladu, že jsou splněny všechny následující podmínky:SaTliší se pouze v typu prvku.Oba
SeaTejsou odkazové typy nebo jsou parametry typu známé jako odkazový typ.Rozšiřující odkaz, pole nebo převod parametru typu existuje z
SenaTe.
Z typu
Spole s výčtovým typemSeelementu na typTpole s typemTeelementu jsou splněny všechny následující podmínky:SaTliší se pouze v typu prvku.Teje základní typ .Se
Z typu
Spole pořadí 1 s výčtovým typemSeprvku , doSystem.Collections.Generic.IList(Of Te),IReadOnlyList(Of Te),ICollection(Of Te),IReadOnlyCollection(Of Te), aIEnumerable(Of Te), za předpokladu, že platí jedna z následujících hodnot:Oba
SeaTejsou odkazové typy nebo jsou parametry typu známé jako odkazový typ, a rozšiřující odkaz, pole nebo převod parametru typu existuje zSeTe; neboTeje základní typSe; neboTeje shodná sSe
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
Tna typT?.Z typu
T?na typS?, kde existuje rozšiřující převod z typuTna typS.Z typu
Tna typS?, kde existuje rozšiřující převod z typuTna typS.Z typu
T?na typ rozhraní, který typTimplementuje.
Převody řetězců
Od
ChardoString.Od
Char()doString.
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
Ttypu na omezeníTxparametru typu nebo cokoliTxmá 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, neboLong.DecimalSingleDoubleOd
Byte,SByte, ,UShort,Short, ,UInteger,Integer,DecimalULongSingleLongneboDoubledo .Boolean
Číselné převody
Od
BytedoSByte.Od
SBytepoByte,UShort,UIntegerneboULong.Od
UShortpoByte,SByteneboShort.Od
ShortpoByte,SByte,UShort,UIntegerneboULong.Od
UIntegerpoByte,SByte,UShort,ShortneboInteger.Od
IntegerpoByte,SByte,UShort,Short,UIntegerneboULong.Od
ULongpoByte,SByte,UShort,Short,UInteger,IntegerneboLong.Od
LongpoByte,SByte,UShort,Short,UInteger,IntegerneboULong.Od
DecimalpoByte,SByte,UShort,Short,UInteger,Integer,ULongneboLong.Od
Singledo ,Byte, ,SByte, ,UShort,ShortUIntegerIntegerULongnebo .LongDecimalOd
DoubledoByte,SByte, ,UShort, ,Short,UInteger,IntegerULongLongDecimal, , nebo .SingleZ čí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 typTpole s typemTeprvku za předpokladu, že platí všechny následující skutečnosti:-
SaTliší se pouze v typu prvku. - Oba
SeaTejsou 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
SedoTe.
-
Z typu pole s typem
SSeelementu na typTpole s výčtovým typemTeelementu jsou splněny všechny následující skutečnosti:-
SaTliší se pouze v typu prvku. -
Seje základní typ ,Tenebo jsou oba různé výčtové typy, které sdílejí stejný základní typ.
-
Z typu
Spole pořadí 1 s výčtovým typemSeprvku , doIList(Of Te),IReadOnlyList(Of Te),ICollection(Of Te)IReadOnlyCollection(Of Te)aIEnumerable(Of Te), za předpokladu, že platí jedna z následujících hodnot:- Oba
SeaTejsou odkazové typy nebo jsou parametry typu známé jako odkazový typ, a zužující odkaz, pole nebo převod parametrů typu existuje zSeTe; nebo -
Seje základní typ ,Tenebo jsou oba různé výčtové typy, které sdílejí stejný základní typ.
- Oba
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 typT.Z typu
T?na typS?, kde existuje zužující převod z typuTna typS.Z typu
Tna typS?, kde existuje zužující převod z typuTna typS.Z typu
S?na typT, kde existuje převod z typuSna typT.
Převody řetězců
Od
StringdoChar.Od
StringdoChar().Od
StringdoBooleana zBooleandoString.Převody mezi
StringaByte, ,UShortSByte,ShortLongUIntegerULongDecimalInteger, ,Singlenebo .DoubleOd
StringdoDatea zDatedoString.
Převody parametrů typu
Od
Objectparametru 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
Ttypu na cokoli, na co má omezeníTxparametru 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:
Nejprve se hodnota převede ze zdrojového typu na typ operandu pomocí vnitřního převodu, pokud je to nutné.
Pak se vyvolá převod definovaný uživatelem.
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ů:
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.
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.
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.
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.
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ů:
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.
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.
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.
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.
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.
Visual Basic language spec