Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Konwersja to proces zmiany wartości z jednego typu na inny. Na przykład wartość typu Integer można przekonwertować na wartość typu lub wartość typu Doublemożna przekonwertować na wartość typu BaseDerived , przy założeniu, że Base zarówno klasy, jak i DerivedDerived dziedziczą z Baseklasy . Konwersje mogą nie wymagać zmiany samej wartości (jak w ostatnim przykładzie) lub mogą wymagać znaczących zmian w reprezentacji wartości (jak w poprzednim przykładzie).
Konwersje mogą być rozszerzane lub zawężane.
Konwersja rozszerzająca to konwersja z typu na inny typ, którego domena wartości jest co najmniej tak duża, jeśli nie większa, niż domena wartości oryginalnego typu. Konwersje rozszerzające nigdy nie powinny zakończyć się niepowodzeniem.
Konwersja zawężania to konwersja z typu na inny typ, którego domena wartości jest mniejsza niż domena wartości oryginalnego typu lub wystarczająco niepowiązana, że podczas konwersji należy zachować dodatkową ostrożność (na przykład podczas konwersji z Integer na String). Zawężenie konwersji, co może wiązać się z utratą informacji, może zakończyć się niepowodzeniem.
Konwersja tożsamości (tj. konwersja typu do samego siebie) i konwersja wartości domyślnej (tj. konwersja z Nothing) jest definiowana dla wszystkich typów.
Niejawne i jawne konwersje
Konwersje mogą być niejawne lub jawne. Konwersje niejawne występują bez żadnej specjalnej składni. Poniżej przedstawiono przykład niejawnej Long konwersji Integer wartości na wartość:
Module Test
Sub Main()
Dim intValue As Integer = 123
Dim longValue As Long = intValue
Console.WriteLine(intValue & " = " & longValue)
End Sub
End Module
Z drugiej strony jawne konwersje wymagają operatorów rzutów. Próba wykonania jawnej konwersji wartości bez operatora rzutowania powoduje błąd czasu kompilacji. W poniższym przykładzie użyto jawnej konwersji, aby przekonwertować Long wartość na Integer wartość.
Module Test
Sub Main()
Dim longValue As Long = 134
Dim intValue As Integer = CInt(longValue)
Console.WriteLine(longValue & " = " & intValue)
End Sub
End Module
Zestaw niejawnych konwersji zależy od środowiska kompilacji i instrukcji Option Strict . Jeśli są używane ścisłe semantyka, tylko konwersje rozszerzające mogą wystąpić niejawnie. Jeśli są używane semantyka permisywna, wszystkie konwersje rozszerzające i zawężające (innymi słowy, wszystkie konwersje) mogą wystąpić niejawnie.
Konwersje logiczne
Chociaż Boolean nie jest typem liczbowym, ma konwersje zawężające do i z typów liczbowych tak, jakby były typem wyliczanym. Literał True konwertuje na literał 255Byte65535 dla , dla UShortUInteger429496729518446744073709551615 , dla , dla ULong, i na wyrażenie -1 dla SByte, , Short, IntegerDecimalLongSinglei .Double Literał False konwertuje na literał 0. Wartość liczbowa zero konwertuje na literał False. Wszystkie inne wartości liczbowe są konwertowane na literał True.
Istnieje konwersja zawężająca z wartości logicznej na ciąg, konwertując wartość na System.Boolean.TrueString wartość lub System.Boolean.FalseString. Istnieje również konwersja zawężająca z String do Boolean: jeśli ciąg był równy TrueString lub FalseString (w bieżącej kulturze, bez uwzględniania wielkości liter), następnie używa odpowiedniej wartości; w przeciwnym razie próbuje przeanalizować ciąg jako typ liczbowy (w szesnastku lub ósemkowym, jeśli to możliwe, jako zmiennoprzecinkowe) i używa powyższych reguł; w przeciwnym razie zgłasza System.InvalidCastExceptionwartość .
Konwersje liczbowe
Konwersje liczbowe istnieją między typami Byte, , UShortUIntegerIntegerShortSByteLongDecimalULongSingle i Doublewszystkimi typami wyliczonymi. Podczas konwertowania wyliczane typy są traktowane tak, jakby były ich typami bazowymi. Podczas konwertowania na typ wyliczony wartość źródłowa nie jest wymagana do zachowania zgodności z zestawem wartości zdefiniowanych w typie wyliczanym. Przykład:
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
Konwersje liczbowe są przetwarzane w czasie wykonywania w następujący sposób:
W przypadku konwersji z typu liczbowego na szerszy typ liczbowy wartość jest po prostu konwertowana na szerszy typ. Konwersje z
UInteger, ,ULongInteger,LonglubDecimaldoSinglelubDoublesą zaokrąglane do najbliższejSinglelubDoublewartości. Chociaż ta konwersja może spowodować utratę dokładności, nigdy nie spowoduje utraty wielkości.W przypadku konwersji z typu całkowitego do innego typu całkowitego lub od
Singletypu ,DoublelubDecimaldo typu całkowitego wynik zależy od tego, czy sprawdzanie przepełnienia liczby całkowitej jest następujące:Jeśli przepełnienie całkowite jest sprawdzane:
Jeśli źródło jest typem całkowitym, konwersja powiedzie się, jeśli argument źródłowy mieści się w zakresie typu docelowego. Konwersja zgłasza
System.OverflowExceptionwyjątek, jeśli argument źródłowy znajduje się poza zakresem typu docelowego.Jeśli źródło ma
Singlewartość ,DoublelubDecimal, wartość źródłowa jest zaokrąglona w górę lub w dół do najbliższej wartości całkowitej, a ta wartość całkowita staje się wynikiem konwersji. Jeśli wartość źródłowa jest równie zbliżona do dwóch wartości całkowitych, wartość jest zaokrąglona do wartości, która ma parzystą liczbę w najmniej znaczącej pozycji cyfrowej. Jeśli wynikowa wartość całkowita znajduje się poza zakresem typu docelowego, zgłaszanySystem.OverflowExceptionjest wyjątek.
Jeśli przepełnienie liczby całkowitej nie jest sprawdzane:
Jeśli źródło jest typem całkowitym, konwersja zawsze się powiedzie i po prostu składa się z odrzucania najbardziej znaczących bitów wartości źródłowej.
Jeśli źródłem jest
Single,DoublelubDecimal, konwersja zawsze się powiedzie i po prostu składa się z zaokrąglania wartości źródłowej do najbliższej wartości całkowitej. Jeśli wartość źródłowa jest równie zbliżona do dwóch wartości całkowitych, wartość jest zawsze zaokrąglona do wartości, która ma liczbę parzystą w najmniej znaczącej pozycji cyfry.
W przypadku konwersji z
DoublenaSinglewartośćDoublewartość jest zaokrąglona do najbliższejSinglewartości.DoubleJeśli wartość jest za mała, aby reprezentować jakoSinglewartość , wynik staje się dodatni zero lub zero ujemne.DoubleJeśli wartość jest zbyt duża, aby reprezentować jakoSinglewartość , wynik staje się dodatnią nieskończonością lub nieskończonością ujemną.DoubleJeśli wartość toNaN, wynik to równieżNaN.W przypadku konwersji z
SinglelubDoublenaDecimalwartość wartość źródłowa jest konwertowana naDecimalreprezentację i zaokrąglana do najbliższej liczby po 28 miejscu dziesiętnym, jeśli jest to wymagane. Jeśli wartość źródłowa jest za mała, aby reprezentować jakoDecimalwartość , wynik stanie się zerowy. Jeśli wartość źródłowa toNaN, nieskończoność lub zbyt duża, aby reprezentować jakoDecimal,System.OverflowExceptionzgłaszany jest wyjątek.W przypadku konwersji z
DoublenaSinglewartośćDoublewartość jest zaokrąglona do najbliższejSinglewartości.DoubleJeśli wartość jest za mała, aby reprezentować jakoSinglewartość , wynik staje się dodatni zero lub zero ujemne.DoubleJeśli wartość jest zbyt duża, aby reprezentować jakoSinglewartość , wynik staje się dodatnią nieskończonością lub nieskończonością ujemną.DoubleJeśli wartość toNaN, wynik to równieżNaN.
Konwersje odwołań
Typy odwołań mogą być konwertowane na typ podstawowy i odwrotnie. Konwersje z typu podstawowego na bardziej pochodny typ kończą się powodzeniem tylko w czasie wykonywania, jeśli przekonwertowana wartość jest wartością null, samym typem pochodnym lub bardziej pochodnym typem.
Typy klas i interfejsów można rzutować do i z dowolnego typu interfejsu. Konwersje między typem a typem interfejsu kończą się powodzeniem tylko w czasie wykonywania, jeśli rzeczywiste typy, których dotyczy, mają relację dziedziczenia lub implementacji. Ponieważ typ interfejsu zawsze będzie zawierać wystąpienie typu pochodzącego z Objectklasy , typ interfejsu może być również zawsze rzutowy do i z Objectklasy .
Uwaga. Nie jest to błąd podczas konwertowania NotInheritable klas na i z interfejsów, które nie są implementowane, ponieważ klasy reprezentujące klasy COM mogą mieć implementacje interfejsu, które nie są znane do czasu wykonywania.
Jeśli konwersja odwołania zakończy się niepowodzeniem w czasie wykonywania, System.InvalidCastException zostanie zgłoszony wyjątek.
Konwersje wariancji odwołań
Interfejsy ogólne lub delegaty mogą mieć parametry typu wariantu, które umożliwiają konwersje między zgodnymi wariantami typu. W związku z tym w czasie wykonywania konwersja z typu klasy lub typu interfejsu na typ interfejsu zgodny z typem interfejsu dziedziczy lub implementuje powodzenie. Podobnie typy delegatów można rzutować do i z typów delegatów zgodnych z wariantami. Na przykład typ delegata
Delegate Function F(Of In A, Out R)(a As A) As R
umożliwia konwersję z F(Of Object, Integer) na F(Of String, Integer). Oznacza to, że delegat F , który przyjmuje Object , może być bezpiecznie używany jako delegat F , który przyjmuje String. Po wywołaniu delegata metoda docelowa będzie oczekiwać obiektu, a ciąg jest obiektem.
Ogólny delegat lub typ S(Of S1,...,Sn) interfejsu jest mówi się, że wariant jest zgodny z interfejsem ogólnym lub typem T(Of T1,...,Tn) delegata, jeśli:
SiTsą konstruowane z tego samego typuU(Of U1,...,Un)ogólnego .Dla każdego parametru
Uxtypu :Jeśli parametr typu został zadeklarowany bez wariancji,
Sxto iTxmusi być tego samego typu.Jeśli parametr typu został zadeklarowany
In, musi istnieć tożsamość rozszerzająca, domyślna, odwołanie, tablica lub konwersja parametru typu zSxnaTx.Jeśli parametr typu został zadeklarowany
Out, musi istnieć tożsamość rozszerzająca, domyślna, odwołanie, tablica lub konwersja parametru typu zTxnaSx.
W przypadku konwertowania z klasy na interfejs ogólny z parametrami typu wariantu, jeśli klasa implementuje więcej niż jeden interfejs zgodny z wariantem, konwersja jest niejednoznaczna, jeśli nie ma konwersji innej niż wariant. Przykład:
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
Anonimowe konwersje delegatów
Gdy wyrażenie sklasyfikowane jako metoda lambda jest ponownie sklasyfikowane jako wartość w kontekście, w którym nie ma typu docelowego (na przykład Dim x = Function(a As Integer, b As Integer) a + b), lub gdy typ docelowy nie jest typem delegata, typ wyrażenia wynikowego jest anonimowym typem delegata równoważnym podpisowi metody lambda. Ten anonimowy typ delegata ma konwersję na dowolny zgodny typ delegata: zgodny typ delegata to dowolny typ delegata, który można utworzyć przy użyciu wyrażenia tworzenia delegata z metodą anonimowego typu delegata Invoke jako parametr. Przykład:
' 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
Należy pamiętać, że typy System.Delegate i System.MulticastDelegate nie są traktowane jako typy delegatów (mimo że wszystkie typy delegatów dziedziczą po nich). Należy również pamiętać, że konwersja typu anonimowego delegata na zgodny typ delegata nie jest konwersją referencyjną.
Konwersje tablic
Oprócz konwersji zdefiniowanych na tablicach ze względu na fakt, że są typami referencyjnymi, istnieje kilka specjalnych konwersji dla tablic.
W przypadku dwóch typów A i , jeśli są to zarówno typy referencyjne, jak i Bparametry typu, które nie są znane jako typy wartości, a jeśli A ma konwersję odwołania, tablicy lub parametru typu do B, konwersja istnieje z tablicy typu A do tablicy typu B o tej samej rangi. Ta relacja jest nazywana kowariancją tablicy. Wariancja tablicy w szczególności oznacza, że element tablicy, którego typ elementu jest rzeczywiście elementem tablicy, którego typem elementu jest BA, pod warunkiem, że oba A typy i B są typami referencyjnymi i które B mają konwersję odwołania lub konwersję tablicy na A. W poniższym przykładzie drugie wywołanie powoduje zgłoszenie wyjątkuF, ponieważ rzeczywisty typ b elementu to String, a nie Object:System.ArrayTypeMismatchException
Module Test
Sub F(ByRef x As Object)
End Sub
Sub Main()
Dim a(10) As Object
Dim b() As Object = New String(10) {}
F(a(0)) ' OK.
F(b(1)) ' Not allowed: System.ArrayTypeMismatchException.
End Sub
End Module
Ze względu na kowariancję tablic, przypisania do elementów tablic typów odwołań obejmują sprawdzanie czasu wykonywania, które gwarantuje, że wartość przypisana do elementu tablicy jest rzeczywiście dozwolonym typem.
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
W tym przykładzie przypisanie metody array(i) w metodzie Fill niejawnie zawiera sprawdzanie czasu wykonywania, które gwarantuje, że obiekt, do którego odwołuje się zmienna value , jest albo Nothing wystąpieniem typu zgodnego z rzeczywistym typem elementu tablicy array. W metodzie Mainpierwsze dwa wywołania metody Fill kończą się powodzeniem, ale trzecie wywołanie powoduje System.ArrayTypeMismatchException zgłoszenie wyjątku podczas wykonywania pierwszego przypisania do array(i)metody . Wyjątek występuje, ponieważ Integer nie można go przechowywać w tablicy String .
Jeśli jednym z typów elementów tablicy jest parametr typu, którego typ okazuje się być typem wartości w czasie wykonywania, System.InvalidCastException zostanie zgłoszony wyjątek. Przykład:
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
Konwersje istnieją również między tablicą typu wyliczonego a tablicą typu wyliczonego typu bazowego lub tablicą innego typu wyliczanego z tym samym typem bazowym, pod warunkiem, że tablice mają tę samą rangę.
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
W tym przykładzie tablica jest konwertowana na i z tablicy Color typu bazowego Byte. Color Konwersja na tablicę Integerklasy będzie jednak błędem, ponieważ Integer nie jest bazowym typem Color.
Tablica rank-1 typu A() ma również konwersję tablicy na typy interfejsów IList(Of B)kolekcji , IReadOnlyList(Of B), ICollection(Of B)IReadOnlyCollection(Of B) i IEnumerable(Of B) znalezionych w System.Collections.Genericpliku , o ile jedna z następujących wartości ma wartość true:
-
Ai są zarówno typami referencyjnymi, jak iBparametrami typu, które nie są znane jako typy wartości; iAmają rozszerzające odwołanie, tablicę lub konwersję parametru typu naB; lub -
AiBsą wyliczane typy tego samego typu bazowego; lub - jeden z
Aelementów iBjest typem wyliczanym, a drugi jest jego typem bazowym.
Każda tablica typu A z dowolną rangą ma również konwersję tablicy na typy interfejsów IListkolekcji nieogólne i ICollectionIEnumerable znalezione w pliku System.Collections.
Możliwe jest iterowanie interfejsów wynikowych przy użyciu metody For Eachlub bezpośrednie wywołanie GetEnumerator metod. W przypadku tablic rank-1 przekonwertowanych ogólnych lub niegenerycznych form IList lub ICollection, można również uzyskać elementy według indeksu. W przypadku tablic rank-1 przekonwertowanych na ogólne lub nieogólne formy IListklasy można również ustawić elementy według indeksu, z zastrzeżeniem tych samych testów współwariancji tablicy środowiska uruchomieniowego, jak opisano powyżej. Zachowanie wszystkich innych metod interfejsu jest niezdefiniowane przez specyfikację języka VB; jest on do bazowego środowiska uruchomieniowego.
Konwersje typów wartości
Wartość typu wartości można przekonwertować na jeden z podstawowych typów odwołań lub typ interfejsu implementowany przez proces nazywany boxingiem. Gdy wartość typu wartości jest w polu, wartość jest kopiowana z lokalizacji, w której znajduje się na stercie programu .NET Framework. Następnie zwracane jest odwołanie do tej lokalizacji na stercie i może być przechowywane w zmiennej typu odwołania. To odwołanie jest również określane jako wystąpienie pola typu wartości. Wystąpienie w polu ma taką samą semantykę jak typ odwołania zamiast typu wartości.
Typy wartości w polu można przekonwertować z powrotem na ich oryginalny typ wartości za pomocą procesu nazywanego rozpboxowaniem. Gdy pole typu wartości jest rozpalane, wartość jest kopiowana ze sterta do lokalizacji zmiennej. Od tego momentu zachowuje się tak, jakby był to typ wartości. W przypadku rozpakowania typu wartości wartość musi być wartością null lub wystąpieniem typu wartości. W przeciwnym razie zgłaszany System.InvalidCastException jest wyjątek. Jeśli wartość jest wystąpieniem typu wyliczonego, ta wartość może być również rozpakowane do typu bazowego typu wyliczanego lub innego typu wyliczanego, który ma ten sam typ bazowy. Wartość null jest traktowana tak, jakby była literałem Nothing.
Aby dobrze obsługiwać typy wartości dopuszczających wartość null, typ System.Nullable(Of T) wartości jest traktowany specjalnie podczas boksowania i rozpakowania. Boxing wartość typu Nullable(Of T) powoduje pole wartości typu T , jeśli właściwość wartości HasValue jest True lub wartość Nothing , jeśli właściwość wartości HasValue jest False. Rozpakowywanie wartości typu TNullable(Of T) powoduje wystąpienie, Nullable(Of T) którego Value właściwość jest wartością w polu i której HasValue właściwością jest True. Wartość Nothing można usunąć z pola wyboru Nullable(Of T) dla dowolnego T elementu i powoduje wyświetlenie wartości, której HasValue właściwość to False. Ponieważ typy wartości w polu zachowują się jak typy odwołań, istnieje możliwość utworzenia wielu odwołań do tej samej wartości. W przypadku typów pierwotnych i wyliczonych typów jest to nieistotne, ponieważ wystąpienia tych typów są niezmienne. Oznacza to, że nie można zmodyfikować boxed wystąpienia tych typów, więc nie można obserwować faktu, że istnieje wiele odwołań do tej samej wartości.
Struktury, z drugiej strony, mogą być modyfikowalne, jeśli jego zmienne wystąpienia są dostępne lub jeśli jego metody lub właściwości modyfikują zmienne wystąpienia. Jeśli jedno odwołanie do struktury skrzynkowej jest używane do modyfikowania struktury, wszystkie odwołania do struktury skrzynkowej będą widzieć zmianę. Ponieważ ten wynik może być nieoczekiwany, gdy wartość typowana jako Object jest kopiowana z jednej lokalizacji do innego typu wartości w polu, zostanie automatycznie sklonowana na stercie zamiast jedynie skopiować odwołania. Przykład:
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
Dane wyjściowe programu to:
Values: 0, 123
Refs: 123, 123
Przypisanie do pola zmiennej val2 lokalnej nie ma wpływu na pole zmiennej val1 lokalnej, ponieważ gdy pole zostało Struct1 przypisane do val2, kopia wartości została wykonana. Z kolei przypisanie ref2.Value = 123 ma wpływ na obiekt, który zarówno ref1 , jak i ref2 odwołuje się.
Uwaga. Kopiowanie struktury nie jest wykonywane w przypadku struktur w polu typowanych, ponieważ System.ValueType nie można opóźnić powiązania elementu System.ValueType.
Istnieje jeden wyjątek od reguły, która typy wartości w polu zostaną skopiowane podczas przypisywania. Jeśli odwołanie typu wartości pola jest przechowywane w innym typie, odwołanie wewnętrzne nie zostanie skopiowane. Przykład:
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
Dane wyjściowe programu to:
Values: 123, 123
Dzieje się tak, ponieważ wartość wewnętrzna nie jest kopiowana podczas kopiowania wartości. W związku z tym zarówno, jak val1.Value i val2.Value mają odwołanie do tego samego typu wartości pola.
Uwaga. Fakt, że typy wartości w polu wewnętrznym nie są kopiowane, jest ograniczeniem systemu typów platformy .NET — aby upewnić się, że wszystkie typy wartości wewnętrznych zostały skopiowane za każdym razem, gdy skopiowana wartość typu Object byłaby zbyt kosztowna.
Jak opisano wcześniej, typy wartości w polu mogą być rozdzielane tylko do ich oryginalnego typu. Typy pierwotne boxed są jednak traktowane specjalnie w przypadku wpisywania jako Object. Można je przekonwertować na dowolny inny typ pierwotny, do którego mają konwersję. Przykład:
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
Zwykle nie można rozpiąć wartości 5 pola Integer do zmiennejByte. Jednak ponieważ Integer i Byte są typami pierwotnymi i mają konwersję, konwersja jest dozwolona.
Należy pamiętać, że konwertowanie typu wartości na interfejs różni się od ogólnego argumentu ograniczonego do interfejsu. Podczas uzyskiwania dostępu do elementów członkowskich interfejsu przy użyciu ograniczonego parametru typu (lub wywoływania metod w systemie Object) boxing nie występuje tak samo, jak w przypadku konwersji typu wartości na interfejs, a dostęp do elementu członkowskiego interfejsu jest uzyskiwany. Załóżmy na przykład, że interfejs ICounter zawiera metodę Increment , która może służyć do modyfikowania wartości. Jeśli ICounter jest używany jako ograniczenie, implementacja Increment metody jest wywoływana z odwołaniem do zmiennej, która Increment została wywołana, a nie kopii pola:
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
Pierwsze wywołanie Increment modyfikuje wartość w zmiennej x. Nie jest to równoważne drugiemu wywołaniu funkcji Increment, które modyfikuje wartość w zamkniętej kopii x. W związku z tym dane wyjściowe programu to:
0
1
1
Konwersje typów wartości dopuszczanych do wartości null
Typ T wartości może konwertować na i z wersji dopuszczanej do wartości null typu . T? Konwersja z T? na T zgłasza System.InvalidOperationException wyjątek, jeśli przekonwertowana wartość to Nothing. Ponadto ma konwersję na typS, T? jeśli T ma wewnętrzną konwersję na S. A jeśli S jest typem wartości, między i istnieją następujące konwersje wewnętrzne między T? i S?:
Konwersja tej samej klasyfikacji (zawężanie lub rozszerzanie) z
T?naS?.Konwersja tej samej klasyfikacji (zawężanie lub rozszerzanie) z
TnaS?.Konwersja zawężająca z
S?doT.
Na przykład istnieje wewnętrzna konwersja rozszerzająca od Integer? do Long? , ponieważ istnieje wewnętrzna konwersja rozszerzająca z Integer na Long:
Dim i As Integer? = 10
Dim l As Long? = i
Podczas konwertowania wartości z T? na S?wartość , jeśli wartość T? to Nothing, wartość parametru S? to Nothing. W przypadku konwersji z S? na lub T? na TS, jeśli wartość lub S? ma Nothingwartość T? , System.InvalidCastException zostanie zgłoszony wyjątek.
Ze względu na zachowanie typu System.Nullable(Of T)bazowego , gdy typ T? wartości dopuszczanej do wartości null jest w polu, wynik jest wartością pola typu T, a nie wartością pola typu T?. I, z drugiej strony, podczas rozpakowania do typu T?wartości dopuszczającej wartość null, wartość zostanie opakowana przez System.Nullable(Of T), i Nothing zostanie rozpakowana do wartości null typu T?. Przykład:
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
Efektem ubocznym tego zachowania jest to, że typ T? wartości dopuszczającej wartość null wydaje się implementować wszystkie interfejsy Tprogramu , ponieważ konwertowanie typu wartości na interfejs wymaga pola typu . W rezultacie T? jest konwertowany na wszystkie interfejsy, które T są konwertowane na. Należy jednak pamiętać, że typ T? wartości dopuszczający wartość null nie implementuje interfejsów T dla celów ogólnego sprawdzania ograniczeń lub odbicia. Przykład:
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
Konwersje ciągów
Konwertowanie Char na String wyniki w ciągu, którego pierwszy znak jest wartością znaku. Konwertowanie String na Char wyniki w postaci, której wartość jest pierwszym znakiem ciągu. Konwertowanie tablicy Char na String wyniki w ciągu, którego znaki są elementami tablicy. Konwertowanie String na tablicę wyników w tablicy Char znaków, których elementy są znakami ciągu.
Dokładne konwersje między String i Boolean, Byte, UShortDecimalSingleDoubleSByteUIntegerDateShortIntegerULongLongi odwrotnie, wykraczają poza zakres tej specyfikacji i są zależne od implementacji z wyjątkiem jednego szczegółów. Konwersje ciągów zawsze uwzględniają bieżącą kulturę środowiska uruchomieniowego. W związku z tym muszą być wykonywane w czasie wykonywania.
Rozszerzanie konwersji
Konwersje rozszerzające nigdy nie przepełniają się, ale mogą wiązać się ze stratą precyzji. Następujące konwersje rozszerzają konwersje:
Konwersje tożsamości/domyślne
Od typu do samego siebie.
Na podstawie anonimowego typu delegata wygenerowanego dla metody lambda przeklasyfikowanie do dowolnego typu delegata z identycznym podpisem.
Od literału
Nothingdo typu.
Konwersje liczbowe
Z
BytedoUShort, ,ShortUIntegerIntegerULongLongDecimalSinglelub .DoubleOd
SBytedoShort,Integer,Long,Decimal,SinglelubDouble.Od
UShortdoUInteger,Integer,ULong,Long,Decimal,SinglelubDouble.Z
ShortdoInteger,Long,DecimalSinglelubDouble.Od
UIntegerdoULong,Long,Decimal,SinglelubDouble.Z
IntegerdoLong,DecimalSinglelubDouble.Z
ULongdoDecimal,SinglelubDouble.Z
LongdoDecimal,SinglelubDouble.Z
DecimaldoSinglelubDouble.Od
SingledoDouble.Od literału
0do wyliczonego typu. (Uwaga. Konwersja z0na dowolny typ wyliczony rozszerza się, aby uprościć flagi testowania. Jeśli na przykładValuesjest typem wyliczonym z wartościąOne, możesz przetestować zmiennąvtypuValues, mówiąc(v And Values.One) = 0.Od wyliczonego typu do bazowego typu liczbowego lub do typu liczbowego, do którego jego podstawowy typ liczbowy ma konwersję rozszerzającą.
Z wyrażenia stałego typu
ULong, ,LongUShortIntegerShortUIntegerBytelubSBytedo węższego typu, pod warunkiem, że wartość wyrażenia stałego mieści się w zakresie typu docelowego. (Uwaga. Konwersje zUIntegerlub doSingle,ULongIntegerlubLongSingleDoubledo lubDecimalSingleDoublelub mogą spowodować utratę precyzji, ale nigdy nie spowoduje utraty wielkości. Inne rozszerzające konwersje liczbowe nigdy nie tracą żadnych informacji).
Konwersje odwołań
Z typu odwołania do typu podstawowego.
Z typu odwołania do typu interfejsu, pod warunkiem, że typ implementuje interfejs lub interfejs zgodny z wariantem.
Z typu interfejsu do
Object.Od typu interfejsu do wariantu zgodnego typu interfejsu.
Z typu delegata do wariantu zgodnego typu delegata. (Uwaga. Wiele innych konwersji odwołań jest implikowane przez te reguły. Na przykład anonimowe delegaty to typy referencyjne dziedziczone z
System.MulticastDelegate; typy tablic to typy referencyjne dziedziczone zSystem.Array; typy anonimowe to typy referencyjne dziedziczone zSystem.Object.)
Konwersje delegatów anonimowych
- Na podstawie anonimowego typu delegata wygenerowanego dla metody lambda przeklasyfikowanie do dowolnego szerszego typu delegata.
Konwersje tablic
Z typu
Stablicy z typemSeelementu do typu tablicy z typemTTeelementu , pod warunkiem, że wszystkie następujące elementy są prawdziwe:SiTróżnią się tylko w typie elementu.Oba
SetypyTei są typami referencyjnymi lub są parametrami typu znanymi jako typ odwołania.Rozszerzenie odwołania, tablicy lub konwersji parametru typu istnieje z
SedoTe.
Z typu
Stablicy z wyliczonym typemSeelementu do typu tablicy z typemTTeelementu , pod warunkiem, że wszystkie następujące elementy są prawdziwe:SiTróżnią się tylko w typie elementu.Tejest podstawowym typemSe.
Z typu
Stablicy rangi 1 z wyliczonym typemSeelementu , doSystem.Collections.Generic.IList(Of Te),IReadOnlyList(Of Te),ICollection(Of Te),IReadOnlyCollection(Of Te)iIEnumerable(Of Te), pod warunkiem, że jedna z następujących wartości ma wartość true:Oba
SetypyTei są typami referencyjnymi lub są parametrami typu znanymi jako typ odwołania, a rozszerzenie odwołania, tablicy lub konwersji parametrów typu istnieje zSedoTe; lubTejest podstawowym typemSe; lubTejest identyczny zSe
Konwersje typu wartości
Od typu wartości do typu podstawowego.
Od typu wartości do typu interfejsu implementuje typ.
Konwersje typu wartości dopuszczanej do wartości null
Od typu
Tdo typuT?.Od typu
T?do typuS?, gdzie istnieje konwersja rozszerzająca z typuTna typS.Od typu
Tdo typuS?, gdzie istnieje konwersja rozszerzająca z typuTna typS.Od typu do typu
T?interfejsu, który implementuje typT.
Konwersje ciągów
Od
ChardoString.Od
Char()doString.
Konwersje parametrów typu
Z parametru typu do
Object.Od parametru typu do ograniczenia typu interfejsu lub dowolnego wariantu interfejsu zgodnego z ograniczeniem typu interfejsu.
Z parametru typu do interfejsu zaimplementowanego przez ograniczenie klasy.
Z parametru typu do wariantu interfejsu zgodnego z interfejsem zaimplementowanym przez ograniczenie klasy.
Z parametru typu do ograniczenia klasy lub podstawowego typu ograniczenia klasy.
Od parametru
Ttypu do ograniczeniaTxparametru typu lub dowolnyTxelement ma konwersję rozszerzającą na.
Zawężanie konwersji
Konwersje zawężające to konwersje, których nie można udowodnić, że zawsze się powiedzie, konwersje, które są znane z utraty informacji, i konwersje między domenami typów wystarczająco różnią się, aby zawęzić notację. Następujące konwersje są klasyfikowane jako konwersje zawężające:
Konwersje logiczne
Z
BooleandoByte, ,SByteUShortShortUIntegerIntegerULongLongDecimalSinglelub .DoubleZ
Byte, ,UShortUIntegerLongIntegerShortSByteDecimalSingleULonglubDoubledo .Boolean
Konwersje liczbowe
Od
BytedoSByte.Z
SBytedoByte,UShort,UIntegerlubULong.Z
UShortdoByte,SBytelubShort.Od
ShortdoByte,SByte,UShort,UIntegerlubULong.Od
UIntegerdoByte,SByte,UShort,ShortlubInteger.Od
IntegerdoByte,SByte,UShort,Short,UIntegerlubULong.Od
ULongdoByte,SByte,UShort,Short,UInteger,IntegerlubLong.Od
LongdoByte,SByte,UShort,Short,UInteger,IntegerlubULong.Z
DecimaldoByte,SByte,UShort,Short,UInteger,Integer,ULonglubLong.Z
SingledoByte, ,SByteUShortShortUIntegerIntegerULongLonglub .DecimalZ
DoubledoByte,SByte,UShortShortUIntegerIntegerULongLong, ,Decimallub .SingleOd typu liczbowego do wyliczonego typu.
Od wyliczonego typu do typu liczbowego jego podstawowy typ liczbowy ma konwersję zawężającą do.
Z wyliczonego typu do innego wyliczonego typu.
Konwersje odwołań
Od typu odwołania do bardziej pochodnego typu.
Z typu klasy do typu interfejsu, pod warunkiem, że typ klasy nie implementuje typu interfejsu ani wariantu typu interfejsu zgodnego z nim.
Od typu interfejsu do typu klasy.
Z typu interfejsu do innego typu interfejsu, pod warunkiem, że nie ma relacji dziedziczenia między dwoma typami i pod warunkiem, że nie są one zgodne z wariantem.
Konwersje delegatów anonimowych
- Na podstawie anonimowego typu delegata wygenerowanego dla metody lambda przeklasyfikowanie do dowolnego węższego typu delegata.
Konwersje tablic
Z typu
Stablicy z typemSeelementu do typu tablicy z typemTTeelementu , pod warunkiem, że wszystkie następujące elementy są prawdziwe:-
SiTróżnią się tylko w typie elementu. - Oba
SetypyTei są typami referencyjnymi lub są parametrami typu, które nie są znane jako typy wartości. - Konwersja parametrów odwołania, tablicy lub typu istnieje od
SedoTe.
-
Z typu
Stablicy z typemSeelementu do typuTtablicy z wyliczonym typemTeelementu , pod warunkiem, że wszystkie następujące elementy są prawdziwe:-
SiTróżnią się tylko w typie elementu. -
Sejest podstawowym typemTe, lub są to oba różne typy wyliczane, które współużytkują ten sam typ bazowy.
-
Z typu
Stablicy rangi 1 z wyliczonym typemSeelementu , doIList(Of Te),ICollection(Of Te)IReadOnlyList(Of Te)iIReadOnlyCollection(Of Te)IEnumerable(Of Te), pod warunkiem, że jedna z następujących wartości ma wartość true:- Oba
SetypyTei są typami referencyjnymi lub są parametrami typu znanymi jako typ odwołania, a zawężenie odwołania, tablicy lub konwersji parametru typu istnieje zSedoTe; lub -
Sejest podstawowym typemTe, lub są to oba różne typy wyliczane, które współużytkują ten sam typ bazowy.
- Oba
Konwersje typu wartości
Z typu odwołania do bardziej pochodnego typu wartości.
Z typu interfejsu do typu wartości, pod warunkiem, że typ wartości implementuje typ interfejsu.
Konwersje typu wartości dopuszczanej do wartości null
Od typu
T?do typuT.Od typu
T?do typuS?, gdzie istnieje konwersja zawężająca z typuTna typS.Od typu
Tdo typuS?, gdzie istnieje konwersja zawężająca z typuTna typS.Od typu
S?do typuT, gdzie istnieje konwersja z typuSna typT.
Konwersje ciągów
Od
StringdoChar.Od
StringdoChar().Od
StringdoBooleani odBooleandoString.Konwersje między
StringiByte,SByte,UShortULongUIntegerShortLongDecimalIntegerSinglelub .DoubleOd
StringdoDatei odDatedoString.
Konwersje parametrów typu
Od
Objectdo parametru typu.Z parametru typu do typu interfejsu, pod warunkiem, że parametr typu nie jest ograniczony do tego interfejsu lub ograniczone do klasy, która implementuje ten interfejs.
Z typu interfejsu do parametru typu.
Z parametru typu do pochodnego typu ograniczenia klasy.
Od parametru
Ttypu do dowolnego ograniczeniaTxparametru typu ma konwersję zawężającą do.
Konwersje parametrów typu
Konwersje parametrów typu są określane przez ograniczenia, jeśli istnieją, wprowadzone na nich. Parametr T typu może być zawsze konwertowany na siebie, do i z Object, i do i z dowolnego typu interfejsu. Należy pamiętać, że jeśli typ jest typem T wartości w czasie wykonywania, konwersja z T na Object lub typ interfejsu będzie konwersją boksu i konwersją z Object lub typem T interfejsu na będzie konwersja rozpboxowania. Parametr typu z ograniczeniem C klasy definiuje dodatkowe konwersje z parametru typu do C i jego klas bazowych i na odwrót. Parametr T typu z ograniczeniem Tx parametru typu definiuje konwersję na Tx i wszystkie Tx konwersje na.
Tablica, której typ elementu jest parametrem typu z ograniczeniem I interfejsu, ma takie same kowariantne konwersje tablicy co tablica, której typ elementu to I, pod warunkiem, że parametr typu ma Class również ograniczenie klasy lub (ponieważ tylko typy elementów tablicy referencyjnej mogą być kowariantne). Tablica, której typ elementu jest parametrem typu z ograniczeniem C klasy, ma takie same kowariantne konwersje tablicy co tablica, której typem elementu jest C.
Powyższe reguły konwersji nie zezwalają na konwersje z nieprzeciętnych parametrów typu na typy inne niż interfejsy, co może być zaskakujące. Przyczyną tego jest zapobieganie nieporozumieniu semantyki takich konwersji. Rozważmy na przykład następującą deklarację:
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
Jeśli konwersja na TInteger wartość została dozwolona, można łatwo oczekiwać, że X(Of Integer).F(7) zwróci 7Lwartość . Jednak nie byłoby tak, ponieważ konwersje liczbowe są brane pod uwagę tylko wtedy, gdy typy są znane jako liczbowe w czasie kompilacji. Aby semantyka było jasne, zamiast tego należy napisać powyższy przykład:
Class X(Of T)
Public Shared Function F(t As T) As Long
Return CLng(CObj(t)) ' OK, conversions permitted
End Function
End Class
konwersje User-Defined
Konwersje wewnętrzne są konwersjami zdefiniowanymi przez język (tj. wymieniony w tej specyfikacji), podczas gdy konwersje zdefiniowane przez użytkownika są definiowane przez przeciążenie CType operatora. Podczas konwertowania między typami, jeśli nie mają zastosowania konwersje wewnętrzne, zostaną uwzględnione konwersje zdefiniowane przez użytkownika. Jeśli istnieje konwersja zdefiniowana przez użytkownika, która jest najbardziej specyficzna dla typów źródłowych i docelowych, zostanie użyta konwersja zdefiniowana przez użytkownika. W przeciwnym razie wynik błędu czasu kompilacji. Najbardziej konkretna konwersja to ta, której operand jest "najbliżej" typu źródłowego i którego typ wyniku jest "najbliżej" typu docelowego. Podczas określania używanej konwersji zdefiniowanej przez użytkownika zostanie użyta najbardziej specyficzna konwersja rozszerzająca; jeśli żadna konwersja rozszerzająca nie jest najbardziej specyficzna, zostanie użyta najbardziej specyficzna konwersja zawężająca. Jeśli nie ma najbardziej konkretnej konwersji zawężającej, konwersja jest niezdefiniowana i występuje błąd czasu kompilacji.
W poniższych sekcjach opisano sposób określania najbardziej określonych konwersji. Używają one następujących terminów:
Jeśli wewnętrzna konwersja rozszerzająca istnieje z typu A na typ B, a jeśli ani AB nie są interfejsami, A to jest uwzględniana przez B, i BobejmujeA.
Najbardziej obejmującym typem w zestawie typów jest jeden typ, który obejmuje wszystkie inne typy w zestawie. Jeśli żaden pojedynczy typ nie obejmuje wszystkich innych typów, zestaw nie ma najbardziej obejmującego typu. W intuicyjnym ujęciu najbardziej obejmującym typem jest "największy" typ w zestawie — jeden typ, do którego można przekonwertować każdy z innych typów za pomocą konwersji rozszerzającej.
Najbardziej obejmującym typem zestawu typów jest jeden typ, który jest obejmujący wszystkie inne typy w zestawie. Jeśli żaden pojedynczy typ nie jest uwzględniany przez wszystkie inne typy, zestaw nie ma najbardziej objętego typu. W intuicyjnym sensie najbardziej obejmującym typem jest "najmniejszy" typ w zestawie — jeden typ, który można przekonwertować na każdy z innych typów poprzez konwersję zawężającą.
Podczas zbierania kandydata konwersji zdefiniowanych przez użytkownika dla typu T?są używane operatory konwersji zdefiniowane przez T użytkownika. Jeśli typ konwertowany na jest również typem wartości dopuszczających wartość null, zostaną zniesione dowolne operatory konwersji zdefiniowane przez Tużytkownika, które obejmują tylko typy wartości innych niż null. Operator konwersji z T do S jest zniesiony, aby być konwersją z T? na S? i jest obliczany przez konwersję T? na T, w razie potrzeby, a następnie ocenianie operatora konwersji zdefiniowanego przez użytkownika z T do S , a następnie konwertowanie S na S?, w razie potrzeby. Jeśli przekonwertowana wartość to Nothing, jednak operator konwersji zniesionej konwertuje bezpośrednio na wartość Nothing typu .S? Przykład:
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
Podczas rozpoznawania konwersji operatory konwersji zdefiniowanych przez użytkownika są zawsze preferowane przez operatory konwersji zniesionej. Przykład:
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
W czasie wykonywania ocena konwersji zdefiniowanej przez użytkownika może obejmować maksymalnie trzy kroki:
Najpierw wartość jest konwertowana z typu źródłowego na typ operandu przy użyciu konwersji wewnętrznej, jeśli to konieczne.
Następnie wywoływana jest konwersja zdefiniowana przez użytkownika.
Na koniec wynik konwersji zdefiniowanej przez użytkownika jest konwertowany na typ docelowy przy użyciu konwersji wewnętrznej, jeśli to konieczne.
Należy pamiętać, że ocena konwersji zdefiniowanej przez użytkownika nigdy nie będzie obejmować więcej niż jednego operatora konwersji zdefiniowanego przez użytkownika.
Najbardziej specyficzna konwersja rozszerzająca
Określenie najbardziej określonego operatora konwersji rozszerzającego zdefiniowanego przez użytkownika między dwoma typami odbywa się, wykonując następujące czynności:
Najpierw zbierane są wszystkie operatory konwersji kandydatów. Operatory konwersji kandydatów to wszystkie operatory konwersji rozszerzające zdefiniowane przez użytkownika w typie źródłowym i wszystkie operatory konwersji rozszerzające zdefiniowane przez użytkownika w typie docelowym.
Następnie wszystkie nie dotyczy operatory konwersji zostaną usunięte z zestawu. Operator konwersji ma zastosowanie do typu źródłowego i typu docelowego, jeśli istnieje wewnętrzny operator konwersji rozszerzającej z typu źródłowego do typu operandu i istnieje wewnętrzny operator konwersji rozszerzającej z wyniku operatora do typu docelowego. Jeśli nie ma odpowiednich operatorów konwersji, nie ma konkretnej konwersji rozszerzającej.
Następnie określa się najbardziej konkretny typ źródła odpowiednich operatorów konwersji:
Jeśli którykolwiek z operatorów konwersji konwertuje bezpośrednio z typu źródłowego, typ źródła jest najbardziej określonym typem źródła.
W przeciwnym razie najbardziej specyficzny typ źródła jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych operatorów konwersji. Jeśli nie można odnaleźć najbardziej objętego typu, nie ma najbardziej specyficznej konwersji rozszerzającej.
Następnie określa się najbardziej konkretny typ docelowy odpowiednich operatorów konwersji:
Jeśli którykolwiek z operatorów konwersji konwertuje bezpośrednio na typ docelowy, typ docelowy jest najbardziej określonym typem docelowym.
W przeciwnym razie najbardziej specyficzny typ docelowy jest najbardziej obejmującym typem w połączonym zestawie typów docelowych operatorów konwersji. Jeśli nie można odnaleźć żadnego typu obejmującego, nie ma najbardziej konkretnej konwersji rozszerzającej.
Następnie, jeśli dokładnie jeden operator konwersji konwertuje z najbardziej określonego typu źródła na najbardziej konkretny typ docelowy, jest to najbardziej konkretny operator konwersji. Jeśli istnieje więcej niż jeden taki operator, nie ma konkretnej konwersji rozszerzającej.
Najbardziej specyficzna konwersja zawężania
Określenie najbardziej określonego operatora konwersji zdefiniowanego przez użytkownika między dwoma typami jest realizowane przy użyciu następujących kroków:
Najpierw zbierane są wszystkie operatory konwersji kandydatów. Operatory konwersji kandydatów są wszystkimi operatorami konwersji zdefiniowanymi przez użytkownika w typie źródłowym i wszystkimi operatorami konwersji zdefiniowanymi przez użytkownika w typie docelowym.
Następnie wszystkie nie dotyczy operatory konwersji zostaną usunięte z zestawu. Operator konwersji ma zastosowanie do typu źródłowego i typu docelowego, jeśli istnieje operator konwersji wewnętrznej z typu źródłowego do typu operandu i istnieje operator konwersji wewnętrznej z wyniku operatora do typu docelowego. Jeśli nie ma odpowiednich operatorów konwersji, nie ma konkretnej konwersji zawężającej.
Następnie określa się najbardziej konkretny typ źródła odpowiednich operatorów konwersji:
Jeśli którykolwiek z operatorów konwersji konwertuje bezpośrednio z typu źródłowego, typ źródła jest najbardziej określonym typem źródła.
W przeciwnym razie, jeśli którykolwiek z operatorów konwersji konwertuje z typów obejmujących typ źródłowy, najbardziej specyficzny typ źródła jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych tych operatorów konwersji. Jeśli nie można odnaleźć najbardziej objętego typu, nie ma najbardziej specyficznej konwersji zawężającej.
W przeciwnym razie najbardziej specyficzny typ źródła jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych operatorów konwersji. Jeśli nie można odnaleźć najbardziej obejmującego typu, nie ma najbardziej specyficznej konwersji zawężającej.
Następnie określa się najbardziej konkretny typ docelowy odpowiednich operatorów konwersji:
Jeśli którykolwiek z operatorów konwersji konwertuje bezpośrednio na typ docelowy, typ docelowy jest najbardziej określonym typem docelowym.
W przeciwnym razie, jeśli którykolwiek z operatorów konwersji konwertuje na typy, które są objęte typem docelowym, najbardziej specyficzny typ docelowy jest najbardziej obejmującym typem w połączonym zestawie typów źródłowych tych operatorów konwersji. Jeśli nie można odnaleźć najbardziej obejmującego typu, nie ma najbardziej specyficznej konwersji zawężającej.
W przeciwnym razie najbardziej specyficzny typ docelowy jest najbardziej obejmującym typem w połączonym zestawie typów docelowych operatorów konwersji. Jeśli nie można odnaleźć najbardziej objętego typu, nie ma najbardziej specyficznej konwersji zawężającej.
Następnie, jeśli dokładnie jeden operator konwersji konwertuje z najbardziej określonego typu źródła na najbardziej konkretny typ docelowy, jest to najbardziej konkretny operator konwersji. Jeśli istnieje więcej niż jeden taki operator, nie istnieje najbardziej specyficzna konwersja zawężania.
Konwersje natywne
Kilka konwersji jest klasyfikowanych jako konwersje natywne , ponieważ są obsługiwane natywnie przez program .NET Framework. Konwersje te są tymi, które można zoptymalizować za pomocą DirectCast operatorów i TryCast konwersji, a także innych specjalnych zachowań. Konwersje sklasyfikowane jako konwersje natywne to: konwersje tożsamości, konwersje domyślne, konwersje odwołań, konwersje tablicy, konwersje typu wartości i konwersje parametrów typu.
Typ dominujący
Biorąc pod uwagę zestaw typów, często jest konieczne w sytuacjach, takich jak wnioskowanie typu, aby określić dominujący typ zestawu. Dominujący typ zestawu typów jest określany przez najpierw usunięcie wszystkich typów, do których co najmniej jeden inny typ nie ma niejawnej konwersji. Jeśli w tym momencie nie ma żadnych typów, nie ma typu dominującego. Dominujący typ jest wówczas najbardziej obejmujący pozostałe typy. Jeśli istnieje więcej niż jeden typ, który jest najbardziej obejmujący, nie ma dominującego typu.
Visual Basic language spec