Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La conversione è il processo di modifica di un valore da un tipo a un altro. Ad esempio, un valore di tipo Integer può essere convertito in un valore di tipo Doubleo un valore di tipo Derived può essere convertito in un valore di tipo Base, presupponendo che Base e Derived siano entrambe classi e Derived ereditano da Base. Le conversioni potrebbero non richiedere la modifica del valore stesso (come nell'ultimo esempio) oppure potrebbero richiedere modifiche significative nella rappresentazione del valore (come nell'esempio precedente).
Le conversioni possono essere più grandi o più strette. Una conversione verso un tipo più grande è una conversione da un tipo a un altro tipo il cui dominio valore è almeno grande, se non più grande, rispetto al dominio del valore del tipo originale. Le conversioni con estensione non dovrebbero mai avere esito negativo. Una conversione di tipo narrowing è una conversione da un tipo a un altro tipo il cui dominio di valore è minore del dominio del valore del tipo originale o sufficientemente non correlato che è necessario prestare particolare attenzione quando si esegue la conversione , ad esempio quando si esegue la conversione da Integer a String. Le conversioni di tipo narrowing, che possono comportare la perdita di informazioni, possono non riuscire.
La conversione di identità (ad esempio una conversione da un tipo a se stessa) e la conversione di valori predefiniti (ad esempio una conversione da Nothing) sono definite per tutti i tipi.
Conversioni implicite ed esplicite
Le conversioni possono essere implicite o esplicite. Le conversioni implicite vengono eseguite senza sintassi speciale. Di seguito è riportato un esempio di conversione implicita di un Integer valore in un Long valore:
Module Test
Sub Main()
Dim intValue As Integer = 123
Dim longValue As Long = intValue
Console.WriteLine(intValue & " = " & longValue)
End Sub
End Module
Le conversioni esplicite, d'altra parte, richiedono operatori cast. Se si tenta di eseguire una conversione esplicita su un valore senza un operatore cast, viene generato un errore in fase di compilazione. Nell'esempio seguente viene utilizzata una conversione esplicita per convertire un Long valore in un Integer valore.
Module Test
Sub Main()
Dim longValue As Long = 134
Dim intValue As Integer = CInt(longValue)
Console.WriteLine(longValue & " = " & intValue)
End Sub
End Module
Il set di conversioni implicite dipende dall'ambiente di compilazione e dall'istruzione Option Strict . Se viene usata una semantica rigorosa, è possibile che vengano eseguite in modo implicito solo conversioni più ampliate. Se viene usata una semantica permissiva, tutte le conversioni verso un tipo più ampio e più ristretto (in altre parole, tutte le conversioni) possono verificarsi in modo implicito.
Conversioni booleane
Anche se Boolean non è un tipo numerico, presenta conversioni verso e verso i tipi numerici come se fosse un tipo enumerato. Il valore letterale True viene convertito nel valore letterale 255 per Byte, 65535 per UShort, 4294967295 per UInteger18446744073709551615ULonge nell'espressione -1 per SByte, ShortLongDecimalIntegerSinglee .Double Il valore letterale False viene convertito nel valore letterale 0. Un valore numerico zero viene convertito nel valore letterale False. Tutti gli altri valori numerici vengono convertiti nel valore letterale True.
È presente una conversione di tipo narrowing da Boolean a String, convertendo in System.Boolean.TrueString o System.Boolean.FalseString. Esiste anche una conversione verso un tipo di dati più piccolo da String a Boolean: se la stringa è uguale a TrueString o FalseString (nelle impostazioni cultura correnti, senza distinzione tra maiuscole e minuscole) usa il valore appropriato; in caso contrario, tenta di analizzare la stringa come tipo numerico (in esadecimale o ottale, se possibile, altrimenti come float) e usa le regole precedenti; in caso contrario, genera System.InvalidCastException.
Conversioni numeriche
Esistono conversioni numeriche tra i tipi Byte, SByte, ShortUShort, , IntegerUInteger, ULongLongDecimalSingle e Doublee tutti i tipi enumerati. Durante la conversione, i tipi enumerati vengono considerati come se fossero i tipi sottostanti. Quando si esegue la conversione in un tipo enumerato, il valore di origine non è necessario per essere conforme al set di valori definiti nel tipo enumerato. Per esempio:
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
Le conversioni numeriche vengono elaborate in fase di esecuzione come indicato di seguito:
Per una conversione da un tipo numerico a un tipo numerico più ampio, il valore viene semplicemente convertito nel tipo più ampio. Le conversioni da
UInteger,ULongInteger, ,LongoDecimalaSingleoDoublevengono arrotondate al valore oDoublepiùSinglevicino. Anche se questa conversione può causare una perdita di precisione, non causerà mai una perdita di grandezza.Per una conversione da un tipo integrale a un altro tipo integrale o da
Single,DoubleoDecimala un tipo integrale, il risultato dipende dal fatto che il controllo dell'overflow integer sia attivo:Se viene controllato l'overflow integer:
Se l'origine è un tipo integrale, la conversione ha esito positivo se l'argomento di origine è compreso nell'intervallo del tipo di destinazione. La conversione genera un'eccezione
System.OverflowExceptionse l'argomento di origine non è compreso nell'intervallo del tipo di destinazione.Se l'origine è
Single,DoubleoDecimal, il valore di origine viene arrotondato verso l'alto o verso il basso al valore integrale più vicino e questo valore integrale diventa il risultato della conversione. Se il valore di origine è ugualmente vicino a due valori integrali, il valore viene arrotondato al valore con un numero pari nella posizione della cifra meno significativa. Se il valore integrale risultante non è compreso nell'intervallo del tipo di destinazione, viene generata un'eccezioneSystem.OverflowException.
Se l'overflow integer non viene controllato:
Se l'origine è un tipo integrale, la conversione ha sempre esito positivo e consiste semplicemente nell'eliminare i bit più significativi del valore di origine.
Se l'origine è
Single,DoubleoDecimal, la conversione ha sempre esito positivo e consiste semplicemente nell'arrotondare il valore di origine verso il valore integrale più vicino. Se il valore di origine è ugualmente vicino a due valori integrali, il valore viene sempre arrotondato al valore con un numero pari nella posizione della cifra meno significativa.
Per una conversione da
DoubleaSingle, ilDoublevalore viene arrotondato al valore piùSinglevicino. Se ilDoublevalore è troppo piccolo per rappresentare comeSingle, il risultato diventa zero positivo o negativo zero. Se ilDoublevalore è troppo grande per rappresentare comeSingle, il risultato diventa infinito positivo o infinito negativo. Se ilDoublevalore èNaN, il risultato è ancheNaN.Per una conversione da
SingleoDoubleinDecimal, il valore di origine viene convertito inDecimalrappresentazione e arrotondato al numero più vicino dopo il 28° separatore decimale, se necessario. Se il valore di origine è troppo piccolo per rappresentare comeDecimal, il risultato diventa zero. Se il valore di origine èNaN, infinito o troppo grande da rappresentare comeDecimal, viene generata un'eccezioneSystem.OverflowException.Per una conversione da
DoubleaSingle, ilDoublevalore viene arrotondato al valore piùSinglevicino. Se ilDoublevalore è troppo piccolo per rappresentare comeSingle, il risultato diventa zero positivo o negativo zero. Se ilDoublevalore è troppo grande per rappresentare comeSingle, il risultato diventa infinito positivo o infinito negativo. Se ilDoublevalore èNaN, il risultato è ancheNaN.
Conversioni di riferimento
I tipi riferimento possono essere convertiti in un tipo di base e viceversa. Le conversioni da un tipo di base a un tipo più derivato hanno esito positivo solo in fase di esecuzione se il valore convertito è un valore Null, il tipo derivato stesso o un tipo più derivato.
È possibile eseguire il cast di tipi di classe e di interfaccia da e verso qualsiasi tipo di interfaccia. Le conversioni tra un tipo e un tipo di interfaccia hanno esito positivo solo in fase di esecuzione se i tipi effettivi coinvolti hanno una relazione di ereditarietà o implementazione. Poiché un tipo di interfaccia conterrà sempre un'istanza di un tipo che deriva da Object, è sempre possibile eseguire il cast di un tipo di interfaccia da e verso Object.
Nota. Non è un errore convertire classi NotInheritable in e da interfacce che non implementa perché le classi che rappresentano classi COM possono avere implementazioni di interfaccia che non sono note fino al runtime.
Se una conversione di riferimento non riesce in fase di esecuzione, viene generata un'eccezione System.InvalidCastException .
Conversioni di varianza di riferimento
Le interfacce generiche o i delegati possono avere parametri di tipo varianti che consentono conversioni tra varianti compatibili del tipo. Pertanto, in fase di esecuzione, una conversione da un tipo di classe o un tipo di interfaccia a un tipo di interfaccia compatibile con un tipo di interfaccia che eredita o implementa avrà esito positivo. Analogamente, è possibile eseguire il cast dei tipi delegati da e verso tipi delegati compatibili con varianti. Ad esempio, il tipo delegato
Delegate Function F(Of In A, Out R)(a As A) As R
consente una conversione da F(Of Object, Integer) a F(Of String, Integer). Ovvero, un delegato F che accetta Object può essere usato in modo sicuro come delegato F che accetta String. Quando il delegato viene richiamato, il metodo di destinazione prevede un oggetto e una stringa è un oggetto .
Un tipo di S(Of S1,...,Sn) interfaccia o delegato generico è detto compatibile con varianti con un'interfaccia generica o un tipo T(Of T1,...,Tn) delegato se:
SeTsono entrambi costruiti dallo stesso tipoU(Of U1,...,Un)generico .Per ogni parametro
Uxdi tipo :Se il parametro di tipo è stato dichiarato senza varianza
SxeTxdeve essere lo stesso tipo.Se il parametro di tipo è stato dichiarato
In, deve essere presente una conversione di parametri di tipo, default, reference, array o type daSxaTx.Se il parametro di tipo è stato dichiarato
Out, deve essere presente una conversione di parametri di tipo, default, reference, array o type daTxaSx.
Quando si esegue la conversione da una classe a un'interfaccia generica con parametri di tipo varianti, se la classe implementa più interfacce compatibili con varianti, la conversione è ambigua se non è presente una conversione non variante. Per esempio:
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
Conversioni di delegati anonimi
Quando un'espressione classificata come metodo lambda viene riclassificata come valore in un contesto in cui non è presente alcun tipo di destinazione ( ad esempio , Dim x = Function(a As Integer, b As Integer) a + b) o dove il tipo di destinazione non è un tipo delegato, il tipo dell'espressione risultante è un tipo delegato anonimo equivalente alla firma del metodo lambda. Questo tipo delegato anonimo ha una conversione a qualsiasi tipo delegato compatibile: un tipo delegato compatibile è qualsiasi tipo delegato che può essere creato usando un'espressione di creazione del delegato con il metodo del Invoke tipo delegato anonimo come parametro. Per esempio:
' 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
Si noti che i tipi System.Delegate e System.MulticastDelegate non sono considerati tipi delegati (anche se tutti i tipi delegati ereditano da essi). Si noti inoltre che la conversione dal tipo delegato anonimo a un tipo delegato compatibile non è una conversione di riferimento.
Conversioni di matrici
Oltre alle conversioni definite sulle matrici in virtù del fatto che sono tipi di riferimento, esistono diverse conversioni speciali per le matrici.
Per due tipi A e B, se sono entrambi tipi riferimento o parametri di tipo non noti come tipi valore e se A ha una conversione di parametri riferimento, matrice o tipo in B, esiste una conversione da una matrice di tipo A a una matrice di tipo B con lo stesso rango. Questa relazione è nota come covarianza della matrice. La covarianza della matrice in particolare indica che un elemento di una matrice il cui tipo di elemento è B in realtà può essere un elemento di una matrice il cui tipo di elemento è A, purché sia A che B siano tipi riferimento e che B dispongano di una conversione di riferimento o di una conversione di matrice in A. Nell'esempio seguente, la seconda chiamata di F fa sì che venga generata un'eccezione System.ArrayTypeMismatchException perché il tipo di elemento effettivo di b è String, non Object:
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
A causa della covarianza della matrice, le assegnazioni agli elementi delle matrici di tipi di riferimento includono un controllo di runtime che garantisce che il valore assegnato all'elemento della matrice sia effettivamente di un tipo consentito.
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
In questo esempio l'assegnazione a array(i) nel metodo Fill include in modo implicito un controllo di runtime che garantisce che l'oggetto a cui fa riferimento la variabile value sia Nothing o un'istanza di un tipo compatibile con il tipo di elemento effettivo della matrice array. Nel metodo Main, le prime due chiamate del metodo Fill hanno esito positivo, ma la terza chiamata genera un'eccezione System.ArrayTypeMismatchException quando si esegue la prima assegnazione a array(i). L'eccezione si verifica perché un oggetto Integer non può essere archiviato in una String matrice.
Se uno dei tipi di elemento matrice è un parametro di tipo il cui tipo risulta essere un tipo valore in fase di esecuzione, verrà generata un'eccezione System.InvalidCastException . Per esempio:
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
Esistono anche conversioni tra una matrice di un tipo enumerato e una matrice del tipo sottostante dell'enumerato o una matrice di un altro tipo enumerato con lo stesso tipo sottostante, a condizione che le matrici abbiano lo stesso rango.
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
In questo esempio, una matrice di Color viene convertita in e da una matrice di Bytetipo sottostante di . Color La conversione in una matrice di Integer, tuttavia, sarà un errore perché Integer non è il tipo sottostante di Color.
Una matrice di tipo A() rank-1 include anche una conversione di matrice nei tipi di IList(Of B)interfaccia di raccolta , , IReadOnlyCollection(Of B)IReadOnlyList(Of B)ICollection(Of B)e IEnumerable(Of B) presenti in System.Collections.Generic, purché una delle condizioni seguenti sia vera:
-
AeBsono entrambi tipi di riferimento o parametri di tipo non noti come tipi di valore; eAha una conversione di parametri di tipo, matrice o di tipo più ampia inB; o -
AeBsono entrambi tipi enumerati dello stesso tipo sottostante; o - uno di
AeBè un tipo enumerato e l'altro è il tipo sottostante.
Qualsiasi matrice di tipo A con qualsiasi rango ha anche una conversione di matrice nei tipi di IListinterfaccia di raccolta non generici e ICollectionIEnumerable disponibile in System.Collections.
È possibile scorrere le interfacce risultanti usando For Eacho richiamare direttamente i GetEnumerator metodi. Nel caso di matrici di rango 1 convertite in forme generiche o non generiche di IList o ICollection, è anche possibile ottenere elementi in base all'indice. Nel caso di matrici rank-1 convertite in forme generiche o non generiche di IList, è anche possibile impostare gli elementi per indice, soggetti agli stessi controlli di covarianza della matrice di runtime come descritto in precedenza. Il comportamento di tutti gli altri metodi di interfaccia non è definito dalla specifica del linguaggio VB; spetta al runtime sottostante.
Conversioni dei tipi di valore
Un valore di tipo valore può essere convertito in uno dei relativi tipi di riferimento di base o in un tipo di interfaccia implementato tramite un processo denominato boxing. Quando viene sottoposto a boxing un valore di tipo valore, il valore viene copiato dalla posizione in cui si trova nell'heap di .NET Framework. Viene quindi restituito un riferimento a questa posizione nell'heap e può essere archiviato in una variabile di tipo riferimento. Questo riferimento viene anche definito istanza boxed del tipo di valore. L'istanza boxed ha la stessa semantica di un tipo riferimento anziché un tipo di valore.
I tipi valore boxed possono essere convertiti di nuovo nel tipo di valore originale tramite un processo denominato unboxing. Quando un tipo di valore boxed è unboxed, il valore viene copiato dall'heap in una posizione variabile. Da quel punto in poi, si comporta come se fosse un tipo di valore. Quando si unboxing di un tipo valore, il valore deve essere un valore Null o un'istanza del tipo di valore. In caso contrario, viene generata un'eccezione System.InvalidCastException . Se il valore è un'istanza di un tipo enumerato, tale valore può anche essere sottoposto a unboxing nel tipo sottostante del tipo enumerato o in un altro tipo enumerato con lo stesso tipo sottostante. Un valore Null viene considerato come se fosse il valore letterale Nothing.
Per supportare correttamente i tipi valore nullable, il tipo di System.Nullable(Of T) valore viene trattato appositamente quando si esegue la conversione boxing e unboxing. Il boxing di un valore di tipo Nullable(Of T) restituisce un valore boxed di tipo T se la proprietà del HasValue valore è True o un valore di Nothing se la proprietà del HasValue valore è False. Unboxing di un valore di tipo T per Nullable(Of T) ottenere un'istanza della Nullable(Of T) cui Value proprietà è il valore boxed e la cui HasValue proprietà è True. Il valore Nothing può essere unboxed in Nullable(Of T) per qualsiasi T oggetto e restituisce un valore la cui HasValue proprietà è False. Poiché i tipi valore boxed si comportano come tipi riferimento, è possibile creare più riferimenti allo stesso valore. Per i tipi primitivi e i tipi enumerati, questo è irrilevante perché le istanze di tali tipi non sono modificabili. Ciò significa che non è possibile modificare un'istanza boxed di tali tipi, quindi non è possibile osservare il fatto che ci sono più riferimenti allo stesso valore.
Le strutture, d'altra parte, possono essere modificabili se le variabili di istanza sono accessibili o se i relativi metodi o proprietà modificano le variabili di istanza. Se si utilizza un riferimento a una struttura boxed per modificare la struttura, tutti i riferimenti alla struttura boxed vedranno la modifica. Poiché questo risultato potrebbe essere imprevisto, quando un valore digitato come Object viene copiato da una posizione a un altro tipo valore boxed verrà clonato automaticamente nell'heap anziché semplicemente avere copiati i relativi riferimenti. Per esempio:
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
L'output del programma è:
Values: 0, 123
Refs: 123, 123
L'assegnazione al campo della variabile locale non influisce val2 sul campo della variabile val1 locale perché quando il boxed Struct1 è stato assegnato a val2, è stata eseguita una copia del valore. Al contrario, l'assegnazione ref2.Value = 123 influisce sull'oggetto a cui ref1 fa riferimento e ref2 .
Nota. La copia della struttura non viene eseguita per le strutture boxed tipate perché System.ValueType non è possibile eseguire l'associazione tardiva di System.ValueType.
Esiste un'eccezione alla regola che i tipi valore boxed verranno copiati in fase di assegnazione. Se un riferimento al tipo di valore boxed viene archiviato all'interno di un altro tipo, il riferimento interno non verrà copiato. Per esempio:
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
L'output del programma è:
Values: 123, 123
Ciò è dovuto al fatto che il valore boxed interno non viene copiato quando il valore viene copiato. Pertanto, sia val1.Value che val2.Value hanno un riferimento allo stesso tipo di valore boxed.
Nota. Il fatto che i tipi di valore interno boxed non vengano copiati è una limitazione del sistema di tipi .NET, per garantire che tutti i tipi di valore interni boxed siano stati copiati ogni volta che un valore di tipo Object è stato copiato sarebbe eccessivamente costoso.
Come descritto in precedenza, i tipi valore boxed possono essere unboxed solo nel tipo originale. I tipi primitivi boxed, tuttavia, vengono trattati appositamente quando tipizzato come Object. Possono essere convertiti in qualsiasi altro tipo primitivo in cui dispongono di una conversione. Per esempio:
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
In genere, il valore 5 boxed Integer non può essere sottoposto a unboxing in una Byte variabile. Tuttavia, poiché Integer e Byte sono tipi primitivi e hanno una conversione, la conversione è consentita.
È importante notare che la conversione di un tipo valore in un'interfaccia è diversa da un argomento generico vincolato a un'interfaccia. Quando si accede ai membri dell'interfaccia in un parametro di tipo vincolato (o chiamando metodi in Object), il boxing non si verifica come avviene quando un tipo di valore viene convertito in un'interfaccia e si accede a un membro di interfaccia. Si supponga, ad esempio, che un'interfaccia ICounter contenga un metodo Increment che può essere usato per modificare un valore. Se ICounter viene usato come vincolo, l'implementazione del Increment metodo viene chiamata con un riferimento alla variabile Increment chiamata su, non una copia boxed:
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
La prima chiamata a Increment modifica il valore nella variabile x. Non è equivalente alla seconda chiamata a Increment, che modifica il valore in una copia incapsulata di x. Di conseguenza, l'output del programma è:
0
1
1
Conversioni di tipi valore nullable
Un tipo di T valore può eseguire la conversione in e dalla versione nullable del tipo , T?. La conversione da T? a T genera un'eccezione System.InvalidOperationException se il valore convertito è Nothing. Inoltre, T? ha una conversione in un tipo S se T ha una conversione intrinseca in S. E se S è un tipo di valore, esistono le conversioni intrinseche seguenti tra T? e S?:
Conversione della stessa classificazione (narrowing o widening) da
T?aS?.Conversione della stessa classificazione (narrowing o widening) da
TaS?.Conversione di tipo narrowing da
S?aT.
Ad esempio, esiste una conversione intrinseca di tipo widening da Integer? a Long? perché esiste una conversione intrinseca di estensione da Integer a Long:
Dim i As Integer? = 10
Dim l As Long? = i
Quando si esegue la conversione da T? a S?, se il valore di T? è Nothing, il valore di sarà .NothingS? Quando si esegue la conversione da a o in , se il valore di T? o S? è Nothing, verrà generata un'eccezioneSystem.InvalidCastException.ST?TS?
A causa del comportamento del tipo System.Nullable(Of T)sottostante , quando viene sottoposto a boxing un tipo valore T? nullable, il risultato è un valore boxed di tipo , non un valore boxed di tipo TT?. Viceversa, quando si esegue unboxing in un tipo valore T?nullable , il valore verrà eseguito il wrapping da System.Nullable(Of T)e Nothing verrà sottoposto a unboxing in un valore Null di tipo T?. Per esempio:
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
Un effetto collaterale di questo comportamento è che un tipo valore T? nullable sembra implementare tutte le interfacce di T, perché la conversione di un tipo valore in un'interfaccia richiede che il tipo venga sottoposto a boxing. Di conseguenza, T? è convertibile in tutte le interfacce convertibili T in . È importante notare, tuttavia, che un tipo valore T? nullable non implementa effettivamente le interfacce di T ai fini del controllo o della reflection di vincoli generici. Per esempio:
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
Conversioni di stringhe
La conversione in String restituisce Char una stringa il cui primo carattere è il valore del carattere. La conversione in Char restituisce String un carattere il cui valore è il primo carattere della stringa. La conversione di una matrice di Char in String restituisce una stringa i cui caratteri sono gli elementi della matrice. La conversione String in una matrice di Char risultati in una matrice di caratteri i cui elementi sono i caratteri della stringa.
Le conversioni esatte tra String e Boolean, Byte, SByteUShort, , ShortLongIntegerUIntegerDecimalSingleULongDouble, Date, , e viceversa, esulano dall'ambito di questa specifica e dipendono dall'implementazione, ad eccezione di un dettaglio. Le conversioni di stringhe considerano sempre le impostazioni cultura correnti dell'ambiente di runtime. Di conseguenza, devono essere eseguite in fase di esecuzione.
Conversioni di tipo in ampliamento
Le conversioni con estensione non superano mai il flusso, ma possono comportare una perdita di precisione. Le conversioni seguenti sono conversioni di tipo widening:
Conversioni identity/default
Da un tipo a se stesso.
Da un tipo delegato anonimo generato per la riclassificazione di un metodo lambda a qualsiasi tipo delegato con una firma identica.
Dal valore letterale
Nothinga un tipo.
Conversioni numeriche
Da
ByteaUShort,ShortUInteger,Integer,ULong,Long,Decimal, ,SingleoDouble.Da
SByteaShort,Integer,Long,Decimal,SingleoDouble.Da
UShortaUInteger,Integer,ULong,Long,Decimal,SingleoDouble.Da
ShortaInteger,LongDecimal,SingleoDouble.Da
UIntegeraULong,Long,Decimal,SingleoDouble.Da
IntegeraLong,DecimalSingleoDouble.Da
ULongaDecimal,SingleoDouble.Da
LongaDecimaloSingleDouble.Da
DecimalaSingleoDouble.Da
SingleaDouble.Dal valore letterale
0a un tipo enumerato. (Nota. La conversione da0a qualsiasi tipo enumerato si estende per semplificare i flag di test. Ad esempio, seValuesè un tipo enumerato con un valoreOne, è possibile testare una variabilevdi tipoValuesdicendo(v And Values.One) = 0.)Da un tipo enumerato al tipo numerico sottostante o a un tipo numerico a cui il tipo numerico sottostante ha una conversione verso un tipo più esteso.
Da un'espressione costante di tipo
ULong,UIntegerLong,Integer, ,UShort,Short,ByteoSBytea un tipo più stretto, a condizione che il valore dell'espressione costante sia compreso nell'intervallo del tipo di destinazione. (Nota. Le conversioni daUIntegeroIntegeraULongSingleLongo aSingleoDoubleDecimala o aSingleoDoublepossono causare una perdita di precisione, ma non causeranno mai una perdita di grandezza. Le altre conversioni numeriche ingrandite non perdono mai informazioni.
Conversioni di riferimento
Da un tipo riferimento a un tipo di base.
Da un tipo riferimento a un tipo di interfaccia, purché il tipo implementi l'interfaccia o un'interfaccia compatibile con varianti.
Da un tipo di interfaccia a
Object.Da un tipo di interfaccia a un tipo di interfaccia compatibile con varianti.
Da un tipo delegato a un tipo delegato compatibile con varianti. (Nota. Molte altre conversioni di riferimento sono implicite in queste regole. Ad esempio, i delegati anonimi sono tipi di riferimento che ereditano da
System.MulticastDelegate. I tipi di matrice sono tipi riferimento che ereditano daSystem.Array. I tipi anonimi sono tipi di riferimento che ereditano daSystem.Object.
Conversioni di delegati anonimi
- Da un tipo delegato anonimo generato per la riclassificazione di un metodo lambda a qualsiasi tipo delegato più ampio.
Conversioni di matrici
Da un tipo di matrice con un tipo di
SSeelemento a un tipo diTmatrice con un tipo diTeelemento , purché tutte le condizioni seguenti siano vere:SeTdifferiscono solo in tipo di elemento.Sia
SecheTesono tipi riferimento o sono parametri di tipo noti come tipo riferimento.Esiste una conversione di un riferimento, una matrice o un parametro di tipo più ampio da
SeaTe.
Da un tipo di matrice con un tipo
SdiSeelemento enumerato a un tipo diTmatrice con un tipo diTeelemento , purché tutte le condizioni seguenti siano vere:SeTdifferiscono solo in tipo di elemento.Teè il tipo sottostante diSe.
Da un tipo di
Smatrice di rango 1 con un tipo diSeelemento enumerato , aSystem.Collections.Generic.IList(Of Te),IReadOnlyCollection(Of Te)IReadOnlyList(Of Te)ICollection(Of Te)eIEnumerable(Of Te), purché uno dei seguenti sia true:Entrambi
Sei tipi eTesono tipi di riferimento o sono parametri di tipo noti come un tipo riferimento e una conversione di parametri di tipo, matrice o di tipo estesa esiste daSeaTe; oTeè il tipo sottostante diSe; oTeè identico aSe
Conversioni dei tipi di valore
Da un tipo valore a un tipo di base.
Da un tipo valore a un tipo di interfaccia implementato dal tipo .
Conversioni di tipi di valore nullable
Da un tipo
Tal tipoT?.Da un tipo a un tipo
S?T?, in cui è presente una conversione verso un tipo più esteso dal tipoTal tipoS.Da un tipo a un tipo
S?T, in cui è presente una conversione verso un tipo più esteso dal tipoTal tipoS.Da un tipo a un tipo
T?di interfaccia implementato dal tipoT.
Conversioni di stringhe
Da
CharaString.Da
Char()aString.
Conversioni dei parametri di tipo
Da un parametro di tipo a
Object.Da un parametro di tipo a un vincolo di tipo di interfaccia o da qualsiasi variante di interfaccia compatibile con un vincolo di tipo di interfaccia.
Da un parametro di tipo a un'interfaccia implementata da un vincolo di classe.
Da un parametro di tipo a una variante di interfaccia compatibile con un'interfaccia implementata da un vincolo di classe.
Da un parametro di tipo a un vincolo di classe o da un tipo di base del vincolo di classe.
Da un parametro di tipo a un vincolo
TTxdi parametro di tipo o qualsiasi elementoTxha una conversione più ampia in .
Conversioni ristrette
Le conversioni di tipo narrowing sono conversioni che non possono essere dimostrate sempre riuscite, conversioni note per perdere informazioni e conversioni in domini di tipi sufficientemente diversi da meritare una notazione ridotta. Le conversioni seguenti vengono classificate come conversioni di tipo narrowing:
Conversioni booleane
Da
BooleanaByte,SByteUShort,Short,UInteger,Integer,ULong,Long, ,Decimal,SingleoDouble.Da
Byte,SByte,UShort,ShortUInteger,Integer,ULongLong, ,Decimal, ,SingleoDoubleaBoolean.
Conversioni numeriche
Da
ByteaSByte.Da
SByteaByte,UShort,UIntegeroULong.Da
UShortaByte,SByteoShort.Da
ShortaByte,SByte,UShort,UIntegeroULong.Da
UIntegeraByte,SByte,UShort,ShortoInteger.Da
IntegeraByte,SByte,UShort,Short,UIntegeroULong.Da
ULongaByte,SByte,UShort,Short,UInteger,IntegeroLong.Da
LongaByte,SByte,UShort,Short,UInteger,IntegeroULong.Da
DecimalaByte,SByte,UShort,Short,UInteger,Integer,ULongoLong.Da
SingleaByte,SByteUShort,Short,UInteger,Integer,ULong, ,LongoDecimal.Da
DoubleaByte,SByte,UShortShort,UInteger,Integer,ULong, ,Long,DecimaloSingle.Da un tipo numerico a un tipo enumerato.
Da un tipo enumerato a un tipo numerico il tipo numerico sottostante ha una conversione di tipo narrowing a.
Da un tipo enumerato a un altro tipo enumerato.
Conversioni di riferimento
Da un tipo riferimento a un tipo più derivato.
Da un tipo di classe a un tipo di interfaccia, a condizione che il tipo di classe non implementi il tipo di interfaccia o una variante del tipo di interfaccia compatibile con esso.
Da un tipo di interfaccia a un tipo di classe.
Da un tipo di interfaccia a un altro tipo di interfaccia, purché non esista alcuna relazione di ereditarietà tra i due tipi e purché non siano compatibili con varianti.
Conversioni di delegati anonimi
- Da un tipo delegato anonimo generato per la riclassificazione di un metodo lambda a qualsiasi tipo delegato più stretto.
Conversioni di matrici
Da un tipo di matrice con un tipo di
SSeelemento , a un tipo diTmatrice con un tipo diTeelemento , a condizione che tutte le condizioni seguenti siano vere:-
SeTdifferiscono solo in tipo di elemento. - Sia
SecheTesono tipi riferimento o sono parametri di tipo non noti come tipi valore. - Esiste una conversione di un riferimento, una matrice o un parametro di tipo ristretto da
SeaTe.
-
Da un tipo di matrice con un tipo di
Selemento a un tipoSeTdi matrice con un tipo diTeelemento enumerato , purché tutte le condizioni seguenti siano vere:-
SeTdifferiscono solo in tipo di elemento. -
Seè il tipo sottostante diTeo sono entrambi tipi enumerati diversi che condividono lo stesso tipo sottostante.
-
Da un tipo di
Smatrice di rango 1 con un tipo diSeelemento enumerato , aIList(Of Te),IReadOnlyList(Of Te)ICollection(Of Te),IReadOnlyCollection(Of Te)eIEnumerable(Of Te), purché sia true uno dei seguenti:- Entrambi
Sei tipi eTesono tipi riferimento o sono parametri di tipo noti come un tipo riferimento e una conversione di parametri di tipo, matrice o di tipo ristretta esiste daSeaTe; o -
Seè il tipo sottostante diTeo sono entrambi tipi enumerati diversi che condividono lo stesso tipo sottostante.
- Entrambi
Conversioni dei tipi di valore
Da un tipo riferimento a un tipo di valore più derivato.
Da un tipo di interfaccia a un tipo valore, a condizione che il tipo valore implementi il tipo di interfaccia.
Conversioni di tipi di valore nullable
Da un tipo a un tipo
T?T.Da un tipo a un tipo
T?S?, in cui è presente una conversione verso un tipo più piccolo dal tipo al tipoTS.Da un tipo a un tipo
TS?, in cui è presente una conversione verso un tipo più piccolo dal tipo al tipoTS.Da un tipo a un tipo
S?T, in cui è presente una conversione dal tipoSal tipoT.
Conversioni di stringhe
Da
StringaChar.Da
StringaChar().Da
StringaBooleane daBooleanaString.Conversioni tra
StringeByte,SByteUShort,ShortIntegerUInteger, ,ULongLong,Decimal,Singleo .DoubleDa
StringaDatee daDateaString.
Conversioni dei parametri di tipo
Da
Objecta un parametro di tipo.Da un parametro di tipo a un tipo di interfaccia, a condizione che il parametro di tipo non sia vincolato a tale interfaccia o vincolato a una classe che implementa tale interfaccia.
Da un tipo di interfaccia a un parametro di tipo.
Da un parametro di tipo a un tipo derivato di un vincolo di classe.
Da un parametro di tipo a qualsiasi vincolo
Tdi parametroTxdi tipo è stata eseguita una conversione verso un tipo più piccolo.
Conversioni dei parametri di tipo
Le conversioni dei parametri di tipo sono determinate dai vincoli, se presenti, inseriti su di essi. Un parametro T di tipo può sempre essere convertito in se stesso, in e da Objecte verso e da qualsiasi tipo di interfaccia. Si noti che se il tipo T è un tipo valore in fase di esecuzione, la conversione da T a Object o un tipo di interfaccia sarà una conversione boxing e la conversione da Object o un tipo di interfaccia in T sarà una conversione unboxing. Un parametro di tipo con un vincolo C di classe definisce conversioni aggiuntive dal parametro di tipo alle C classi di base e viceversa. Un parametro T di tipo con un vincolo Tx di parametro di tipo definisce una conversione in Tx e qualsiasi elemento Tx converte in .
Una matrice il cui tipo di elemento è un parametro di tipo con un vincolo I di interfaccia ha le stesse conversioni di matrice covariante di una matrice il cui tipo di elemento è I, a condizione che il parametro di tipo abbia anche un Class vincolo di classe o (poiché solo i tipi di elemento matrice di riferimento possono essere covarianti). Una matrice il cui tipo di elemento è un parametro di tipo con un vincolo C di classe ha le stesse conversioni di matrice covariante di una matrice il cui tipo di elemento è C.
Le regole di conversione precedenti non consentono conversioni da parametri di tipo non vincolato a tipi non di interfaccia, che possono essere sorprendenti. Questo è il motivo per evitare confusione sulla semantica di tali conversioni. Si consideri ad esempio la dichiarazione seguente:
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
Se la conversione di T in Integer fosse consentita, si potrebbe facilmente aspettarsi che X(Of Integer).F(7) restituisca 7L. Tuttavia, non lo sarebbe, perché le conversioni numeriche vengono considerate solo quando i tipi sono noti come numerici in fase di compilazione. Per rendere chiara la semantica, l'esempio precedente deve invece essere scritto:
Class X(Of T)
Public Shared Function F(t As T) As Long
Return CLng(CObj(t)) ' OK, conversions permitted
End Function
End Class
conversioni User-Defined
Le conversioni intrinseche sono conversioni definite dal linguaggio ,ad esempio elencate in questa specifica, mentre le conversioni definite dall'utente vengono definite eseguendo l'overload dell'operatore CType . Quando si esegue la conversione tra tipi, se non sono applicabili conversioni intrinseche, verranno considerate le conversioni definite dall'utente. Se è presente una conversione definita dall'utente più specifica per i tipi di origine e di destinazione, verrà usata la conversione definita dall'utente. In caso contrario, viene restituito un errore in fase di compilazione. La conversione più specifica è quella il cui operando è "più vicino" al tipo di origine e il cui tipo di risultato è "più vicino" al tipo di destinazione. Quando si determina la conversione definita dall'utente da usare, verrà usata la conversione più specifica di ampliamento; se non è più specifica alcuna conversione verso un tipo di dati più esteso, verrà usata la conversione di tipo narrowing più specifica. Se non è presente una conversione più specifica di narrowing, la conversione non è definita e si verifica un errore in fase di compilazione.
Le sezioni seguenti illustrano come vengono determinate le conversioni più specifiche. Usano i termini seguenti:
Se esiste una conversione intrinseca di estensione da un tipo a un tipo BA e se non AB sono né interfacce, A viene incluso da Be BincludeA .
Il tipo più incluso in un set di tipi è quello che include tutti gli altri tipi nel set. Se nessun tipo singolo include tutti gli altri tipi, il set non include più il tipo. In termini intuitivi, il tipo più incluso è il tipo "più grande" nel set, ovvero quello in cui ognuno degli altri tipi può essere convertito tramite una conversione verso un tipo più grande.
Il tipo più incluso in un set di tipi è quello incluso in tutti gli altri tipi del set. Se nessun singolo tipo è incluso in tutti gli altri tipi, il set non include più tipi. In termini intuitivi, il tipo più incluso è il tipo "più piccolo" nel set, ovvero quello che può essere convertito in ognuno degli altri tipi tramite una conversione verso un tipo più piccolo.
Quando si raccolgono le conversioni candidate definite dall'utente per un tipo T?, vengono invece usati gli operatori di conversione definiti dall'utente definiti da T . Se il tipo convertito in è anche un tipo valore nullable, vengono lifted uno degli operatori di Tconversioni definiti dall'utente che coinvolgono solo tipi valore non nullable. Un operatore di conversione da T a S viene sollevato in modo da essere una conversione da T? a S? e viene valutato convertendo TT? in , se necessario, quindi valutando l'operatore di conversione definito dall'utente da T a S e quindi convertendo S in S?, se necessario. Se il valore convertito è Nothing, tuttavia, un operatore di conversione lifted converte direttamente in un valore tipizzato Nothing come S?. Per esempio:
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
Quando si risolvono le conversioni, gli operatori di conversione definiti dall'utente sono sempre preferiti rispetto agli operatori di conversione lifted. Per esempio:
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
In fase di esecuzione, la valutazione di una conversione definita dall'utente può comportare fino a tre passaggi:
In primo luogo, il valore viene convertito dal tipo di origine al tipo di operando usando una conversione intrinseca, se necessario.
Viene quindi richiamata la conversione definita dall'utente.
Infine, il risultato della conversione definita dall'utente viene convertito nel tipo di destinazione usando una conversione intrinseca, se necessario.
È importante notare che la valutazione di una conversione definita dall'utente non comporta mai più di un operatore di conversione definito dall'utente.
Conversione più specifica dell'estensione
Per determinare l'operatore di conversione con estensione più definito dall'utente tra due tipi, seguire questa procedura:
Innanzitutto, vengono raccolti tutti gli operatori di conversione candidati. Gli operatori di conversione candidati sono tutti gli operatori di conversione con estensione definiti dall'utente nel tipo di origine e tutti gli operatori di conversione con estensione più ampia definiti dall'utente nel tipo di destinazione.
Tutti gli operatori di conversione non applicabili vengono quindi rimossi dal set. Un operatore di conversione è applicabile a un tipo di origine e a un tipo di destinazione se è presente un operatore di conversione intrinseco verso un tipo di origine verso il tipo di operando ed è presente un operatore di conversione intrinseco verso l'ampliamento dal risultato dell'operatore al tipo di destinazione. Se non sono presenti operatori di conversione applicabili, non è presente alcuna conversione più specifica per l'ampliamento.
Viene quindi determinato il tipo di origine più specifico degli operatori di conversione applicabili:
Se uno degli operatori di conversione esegue la conversione direttamente dal tipo di origine, il tipo di origine è il tipo di origine più specifico.
In caso contrario, il tipo di origine più specifico è il tipo più incluso nel set combinato di tipi di origine degli operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non esiste una conversione più ampia specifica.
Viene quindi determinato il tipo di destinazione più specifico degli operatori di conversione applicabili:
Se uno degli operatori di conversione viene convertito direttamente nel tipo di destinazione, il tipo di destinazione è il tipo di destinazione più specifico.
In caso contrario, il tipo di destinazione più specifico è il tipo più incluso nel set combinato di tipi di destinazione degli operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non esiste una conversione più ampia specifica.
Quindi, se esattamente un operatore di conversione converte dal tipo di origine più specifico al tipo di destinazione più specifico, questo è l'operatore di conversione più specifico. Se esiste più di un operatore di questo tipo, non è presente alcuna conversione più specifica per l'ampliamento.
Conversione più specifica di restringimento
Per determinare l'operatore di conversione con restringimento definito dall'utente più specifico tra due tipi, seguire questa procedura:
Innanzitutto, vengono raccolti tutti gli operatori di conversione candidati. Gli operatori di conversione candidati sono tutti gli operatori di conversione definiti dall'utente nel tipo di origine e tutti gli operatori di conversione definiti dall'utente nel tipo di destinazione.
Tutti gli operatori di conversione non applicabili vengono quindi rimossi dal set. Un operatore di conversione è applicabile a un tipo di origine e a un tipo di destinazione se è presente un operatore di conversione intrinseco dal tipo di origine al tipo di operando e esiste un operatore di conversione intrinseco dal risultato dell'operatore al tipo di destinazione. Se non sono presenti operatori di conversione applicabili, non è presente alcuna conversione di tipo narrowing più specifica.
Viene quindi determinato il tipo di origine più specifico degli operatori di conversione applicabili:
Se uno degli operatori di conversione esegue la conversione direttamente dal tipo di origine, il tipo di origine è il tipo di origine più specifico.
In caso contrario, se uno degli operatori di conversione esegue la conversione da tipi che includono il tipo di origine, il tipo di origine più specifico è il tipo più incluso nel set combinato di tipi di origine di tali operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non esiste una conversione più specifica di narrowing.
In caso contrario, il tipo di origine più specifico è il tipo più incluso nel set combinato di tipi di origine degli operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non è presente alcuna conversione più specifica di tipo narrowing.
Viene quindi determinato il tipo di destinazione più specifico degli operatori di conversione applicabili:
Se uno degli operatori di conversione viene convertito direttamente nel tipo di destinazione, il tipo di destinazione è il tipo di destinazione più specifico.
In caso contrario, se uno degli operatori di conversione viene convertito in tipi inclusi nel tipo di destinazione, il tipo di destinazione più specifico è il tipo più incluso nel set combinato di tipi di origine di tali operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non è presente alcuna conversione più specifica di tipo narrowing.
In caso contrario, il tipo di destinazione più specifico è il tipo più incluso nel set combinato di tipi di destinazione degli operatori di conversione. Se non è possibile trovare alcun tipo più incluso, non esiste una conversione più specifica di narrowing.
Quindi, se esattamente un operatore di conversione converte dal tipo di origine più specifico al tipo di destinazione più specifico, questo è l'operatore di conversione più specifico. Se esiste più di un operatore di questo tipo, non esiste alcuna conversione più specifica di narrowing.
Conversioni native
Diverse conversioni vengono classificate come conversioni native perché sono supportate in modo nativo da .NET Framework. Queste conversioni sono quelle che possono essere ottimizzate tramite l'uso degli DirectCast operatori di conversione e TryCast , nonché altri comportamenti speciali. Le conversioni classificate come conversioni native sono: conversioni di identità, conversioni predefinite, conversioni di riferimento, conversioni di matrici, conversioni di tipi di valore e conversioni di parametri di tipo.
Tipo dominante
Dato un set di tipi, spesso è necessario in situazioni come l'inferenza del tipo per determinare il tipo dominante del set. Il tipo dominante di un set di tipi è determinato dalla prima rimozione di tutti i tipi a cui uno o più tipi non hanno una conversione implicita. Se non sono presenti tipi lasciati a questo punto, non esiste alcun tipo dominante. Il tipo dominante è quindi il più compreso tra i tipi rimanenti. Se sono presenti più tipi più inclusi, non esiste alcun tipo dominante.
Visual Basic language spec