Freigeben über


Konvertierungen in Visual Basic

Konvertierung ist der Prozess des Änderns eines Werts von einem Typ in einen anderen. Beispielsweise kann ein Typwert Integer in einen Typwert Doublekonvertiert werden, oder ein Typwert Derived kann in einen Typwert Basekonvertiert werden, vorausgesetzt, dass Base es sich um Klassen handelt Derived und Derived von Basedenen geerbt wird. Konvertierungen erfordern möglicherweise nicht, dass sich der Wert selbst ändert (wie im letzten Beispiel), oder sie erfordern erhebliche Änderungen in der Wertdarstellung (wie im vorherigen Beispiel).

Konvertierungen können entweder verbreitern oder verengt werden. Eine Erweiterungskonvertierung ist eine Konvertierung von einem Typ in einen anderen Typ, dessen Wertdomäne mindestens so groß ist, wenn nicht größer als die Wertdomäne des ursprünglichen Typs. Die Verbreiterungskonvertierungen sollten niemals fehlschlagen. Bei einer schmalen Konvertierung handelt es sich um eine Konvertierung von einem Typ in einen anderen Typ, dessen Wertdomäne entweder kleiner als die Wertdomäne des ursprünglichen Typs oder ausreichend nicht mit der Verbindung verbunden ist, die beim Konvertieren der Konvertierung (z. B. beim Konvertieren von Integer in String) erforderlich ist. Die Verengung von Konvertierungen, die zu Einem Verlust von Informationen führen können, kann fehlschlagen.

Die Identitätskonvertierung (d. h. eine Konvertierung von einem Typ in sich) und die Standardwertkonvertierung (d. h. eine Konvertierung von Nothing) werden für alle Typen definiert.

Implizite und explizite Konvertierungen

Konvertierungen können implizit oder explizit sein. Implizite Konvertierungen treten ohne spezielle Syntax auf. Im Folgenden sehen Sie ein Beispiel für die implizite Konvertierung eines Integer Werts in einen Long Wert:

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

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

Explizite Konvertierungen erfordern dagegen Umwandlungsoperatoren. Wenn Sie versuchen, eine explizite Konvertierung für einen Wert ohne Umwandlungsoperator durchzuführen, tritt ein Kompilierungszeitfehler auf. Im folgenden Beispiel wird eine explizite Konvertierung verwendet, um einen Long Wert in einen Integer Wert zu konvertieren.

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

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

Der Satz impliziter Konvertierungen hängt von der Kompilierungsumgebung und der Option Strict Anweisung ab. Wenn strenge Semantik verwendet wird, können nur Verbreiterungskonvertierungen implizit auftreten. Wenn zulässige Semantik verwendet wird, können alle Verbreiterungs- und Eingrenzungskonvertierungen (mit anderen Worten alle Konvertierungen) implizit auftreten.

Boolesche Konvertierungen

Obwohl Boolean es sich nicht um einen numerischen Typ handelt, gibt es schmale Konvertierungen in und aus den numerischen Typen, als ob es sich um einen aufgezählten Typ handelt. Das Literal True wird in das Literal 255 für , 65535 for ByteUShort, 184467440737095516154294967295 for UInteger, und ULongin den Ausdruck -1 für SByte, Short, , , LongInteger, Decimal, , , und .DoubleSingle Das Literal False wird in das Literal 0konvertiert. Ein numerischer Nullwert wird in das Literal Falsekonvertiert. Alle anderen numerischen Werte werden in das Literal Truekonvertiert.

Es gibt eine schmale Konvertierung von Boolean in String, die in eine oder System.Boolean.FalseStringmehrere System.Boolean.TrueString Zeichenfolgen konvertiert wird. Es gibt auch eine Schmalungskonvertierung von String zu Boolean: Wenn die Zeichenfolge gleich TrueString oder FalseString (in der aktuellen Kultur, Groß-/Kleinschreibung ohne Berücksichtigung) ist, wird der entsprechende Wert verwendet. Andernfalls wird versucht, die Zeichenfolge als numerischen Typ zu analysieren (wenn möglich, andernfalls als Gleitkomma), und verwendet die oben genannten Regeln. Andernfalls wird die Zeichenfolge ausgelöst System.InvalidCastException.

Numerische Konvertierungen

Numerische Konvertierungen bestehen zwischen den Typen Byte, , SByte, UShort, Short, UInteger, , Integer, ULong, Long, Decimal, und Single , und , und Doublealle aufgezählten Typen. Beim Konvertieren werden aufgezählte Typen so behandelt, als wären sie ihre zugrunde liegenden Typen. Beim Konvertieren in einen Aufzählungstyp ist der Quellwert nicht erforderlich, um den im Aufzählungstyp definierten Wertesatz zu entsprechen. Beispiel:

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

Numerische Konvertierungen werden zur Laufzeit wie folgt verarbeitet:

  • Bei einer Konvertierung von einem numerischen Typ in einen breiteren numerischen Typ wird der Wert einfach in den breiteren Typ konvertiert. Konvertierungen von UInteger, Integer, ULong, oder Longzu Single oder DecimalDouble werden auf den nächsten Single oder Double Wert gerundet. Obwohl diese Konvertierung zu einem Genauigkeitsverlust führen kann, wird sie niemals zu einem Verlust der Größe führen.

  • Bei einer Konvertierung von einem integralen Typ in einen anderen integralen Typ oder von , Doubleoder von Single, oder Decimal zu einem integralen Typ hängt das Ergebnis davon ab, ob die Überlaufüberprüfung für ganze Zahlen aktiviert ist:

    Wenn der ganzzahlige Überlauf aktiviert wird:

    • Wenn es sich bei der Quelle um einen integralen Typ handelt, ist die Konvertierung erfolgreich, wenn sich das Quellargument innerhalb des Bereichs des Zieltyps befindet. Die Konvertierung löst eine System.OverflowException Ausnahme aus, wenn sich das Quellargument außerhalb des Bereichs des Zieltyps befindet.

    • Wenn die Quelle oder DoubleDecimalder Quellwert Singleauf den nächsten integralen Wert aufgerundet wird und dieser integrale Wert das Ergebnis der Konvertierung wird. Wenn der Quellwert gleich zwei integralen Werten entspricht, wird der Wert auf den Wert gerundet, der eine gerade Zahl in der am wenigsten signifikanten Position aufweist. Wenn sich der resultierende integrale Wert außerhalb des Zieltyps befindet, wird eine System.OverflowException Ausnahme ausgelöst.

    Wenn der ganzzahlige Überlauf nicht überprüft wird:

    • Wenn es sich bei der Quelle um einen integralen Typ handelt, ist die Konvertierung immer erfolgreich und besteht einfach darin, die wichtigsten Bits des Quellwerts zu verwerfen.

    • Wenn die Quelle , Doubleoder Decimal, die Konvertierung immer erfolgreich ist Singleund einfach besteht aus dem Runden des Quellwerts auf den nächsten integralen Wert. Wenn der Quellwert gleich zwei integralen Werten entspricht, wird der Wert immer auf den Wert gerundet, der eine gerade Zahl in der am wenigsten signifikanten Position aufweist.

  • Bei einer Konvertierung von Double in " in Single" wird der Double Wert auf den nächsten Single Wert gerundet. Wenn der Double Wert zu klein ist, um als ein SingleWert darzustellen, wird das Ergebnis zu positiver Null oder negativer Null. Wenn der Double Wert zu groß ist, um als ein SingleWert darzustellen, wird das Ergebnis zu positiver Unendlichkeit oder negativer Unendlichkeit. Wenn der Double Wert lautet NaN, ist das Ergebnis auch NaN.

  • Bei einer Konvertierung von Single oder Double in " in Decimal" wird der Quellwert in Darstellung konvertiert Decimal und bei Bedarf auf die nächste Zahl gerundet. Wenn der Quellwert zu klein ist, um als ein DecimalObjekt darzustellen, wird das Ergebnis null. Wenn der Quellwert NaN, unendlich oder zu groß ist, um als Eine Decimaldarzustellen, wird eine System.OverflowException Ausnahme ausgelöst.

  • Bei einer Konvertierung von Double in " in Single" wird der Double Wert auf den nächsten Single Wert gerundet. Wenn der Double Wert zu klein ist, um als ein SingleWert darzustellen, wird das Ergebnis zu positiver Null oder negativer Null. Wenn der Double Wert zu groß ist, um als ein SingleWert darzustellen, wird das Ergebnis zu positiver Unendlichkeit oder negativer Unendlichkeit. Wenn der Double Wert lautet NaN, ist das Ergebnis auch NaN.

Referenzkonvertierungen

Referenztypen können in einen Basistyp konvertiert werden und umgekehrt. Konvertierungen von einem Basistyp zu einem abgeleiteten Typ sind zur Laufzeit nur erfolgreich, wenn der zu konvertierende Wert ein NULL-Wert, der abgeleitete Typ selbst oder ein abgeleiteter Typ ist.

Klassen- und Schnittstellentypen können in einen beliebigen Schnittstellentyp und von jedem Schnittstellentyp umgegossen werden. Konvertierungen zwischen einem Typ und einem Schnittstellentyp sind zur Laufzeit nur erfolgreich, wenn die tatsächlich beteiligten Typen eine Vererbungs- oder Implementierungsbeziehung aufweisen. Da ein Schnittstellentyp immer eine Instanz eines Typs enthält, von Objectdem abgeleitet wird, kann ein Schnittstellentyp auch immer in und von diesen Objectumgeformt werden.

Hinweis: Es ist kein Fehler, eine NotInheritable Klassen in und von Schnittstellen zu konvertieren, die nicht implementiert werden, da Klassen, die COM-Klassen darstellen, Schnittstellenimplementierungen aufweisen, die bis zur Laufzeit nicht bekannt sind.

Wenn zur Laufzeit eine Verweiskonvertierung fehlschlägt, wird eine System.InvalidCastException Ausnahme ausgelöst.

Referenzabweichungskonvertierungen

Generische Schnittstellen oder Stellvertretungen verfügen möglicherweise über Variantentypparameter, die Konvertierungen zwischen kompatiblen Varianten des Typs ermöglichen. Daher wird zur Laufzeit eine Konvertierung von einem Klassentyp oder einem Schnittstellentyp in einen Schnittstellentyp ausgeführt, der mit einem Schnittstellentyp kompatibel ist, von dem er erbt oder implementiert wird. Ebenso können Stellvertretungstypen in variantenkompatible Delegattypen und aus diesen übertragen werden. Beispiel: Der Delegattyp

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

würde eine Konvertierung von F(Of Object, Integer) zu F(Of String, Integer). Das heißt, eine Stellvertretung F , die Object sicher als Stellvertretung F verwendet werden kann, die akzeptiert String. Wenn der Delegat aufgerufen wird, erwartet die Zielmethode ein Objekt, und eine Zeichenfolge ist ein Objekt.

Ein generischer Delegat- oder Schnittstellentyp S(Of S1,...,Sn) soll mit einer generischen Schnittstelle oder einem Stellvertretungstyp T(Of T1,...,Tn) kompatibel sein, wenn:

  • S und T beide aus demselben generischen Typ U(Of U1,...,Un)erstellt werden.

  • Für jeden Typparameter Ux:

    • Wenn der Typparameter ohne Varianz Sx deklariert wurde, Tx muss derselbe Typ sein.

    • Wenn der Typparameter deklariert In wurde, muss es eine Erweiterungsidentität, eine Standard-, Verweis-, Array- oder Typparameterkonvertierung von Sx zu Tx.

    • Wenn der Typparameter deklariert Out wurde, muss es eine Erweiterungsidentität, eine Standard-, Verweis-, Array- oder Typparameterkonvertierung von Tx zu Sx.

Wenn die Klasse von einer Klasse in eine generische Schnittstelle mit Variantentypparametern konvertiert wird, wenn die Klasse mehr als eine variantkompatible Schnittstelle implementiert, ist die Konvertierung mehrdeutig, wenn keine Nicht-Variant-Konvertierung vorhanden ist. Beispiel:

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

Konvertierungen anonymer Stellvertretungen

Wenn ein ausdruck, der als Lambda-Methode klassifiziert wird, in einem Kontext, in dem kein Zieltyp vorhanden ist (z Dim x = Function(a As Integer, b As Integer) a + b. B. ), oder wenn der Zieltyp kein Delegattyp ist, ist der Typ des resultierenden Ausdrucks ein anonymer Delegattyp, der der Signatur der Lambda-Methode entspricht. Dieser anonyme Delegattyp weist eine Konvertierung in jeden kompatiblen Delegattyp auf: Ein kompatibler Delegattyp ist jeder Delegattyp, der mithilfe eines Delegaterstellungsausdrucks mit der Methode des anonymen Delegattyps Invoke als Parameter erstellt werden kann. Beispiel:

' 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

Beachten Sie, dass die Typen System.Delegate und System.MulticastDelegate nicht selbst Stellvertretungstypen gelten (auch wenn alle Stellvertretungstypen von ihnen erben). Beachten Sie außerdem, dass die Konvertierung von anonymem Delegattyp in einen kompatiblen Delegattyp keine Referenzkonvertierung ist.

Arraykonvertierungen

Neben den Konvertierungen, die auf Arrays definiert sind, aufgrund der Tatsache, dass sie Referenztypen sind, gibt es für Arrays mehrere spezielle Konvertierungen.

Bei zwei Typen und , wenn sie sowohl Bezugstypen A als auch Typparameter sind, die nicht als Werttypen bekannt sind, und wenn A ein Bezug, array oder Typparameter konvertiert Bwird, ist eine Konvertierung von einem Array vom Typ A in ein Array vom Typ B mit demselben Rang vorhanden.B Diese Beziehung wird als Arraykovarianz bezeichnet. Die Arraykovarianz bedeutet insbesondere, dass ein Element eines Arrays, dessen Elementtyp tatsächlich ein Element eines Arrays ist, dessen Elementtyp vorhanden istB, vorausgesetzt, dass sowohl Bezugstypen als auch BA Referenztypen sind und B eine Bezugskonvertierung oder Arraykonvertierung aufweisenA.A Im folgenden Beispiel bewirkt der zweite Aufruf einer F Ausnahme, dass eine System.ArrayTypeMismatchException Ausnahme ausgelöst wird, da der tatsächliche Elementtyp b lautet String, nicht 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

Aufgrund der Arraykovarianz enthalten Zuordnungen zu Elementen des Referenztyparrays eine Laufzeitüberprüfung, mit der sichergestellt wird, dass der dem Arrayelement zugewiesene Wert tatsächlich von einem zulässigen Typ ist.

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 diesem Beispiel enthält die Zuordnung array(i) zur Methode Fill implizit eine Laufzeitüberprüfung, die sicherstellt, dass das objekt, auf das von der Variablen value verwiesen wird, entweder Nothing oder eine Instanz eines Typs ist, der mit dem tatsächlichen Elementtyp des Arrays arraykompatibel ist. Bei der Methode ist der erste Aufruf der Methode MainFill erfolgreich, der dritte Aufruf bewirkt jedoch, dass beim Ausführen der ersten Zuordnung array(i)eine System.ArrayTypeMismatchException Ausnahme ausgelöst wird. Die Ausnahme tritt auf, da ein Integer Array nicht gespeichert String werden kann.

Wenn einer der Arrayelementtypen ein Typparameter ist, dessen Typ sich als Werttyp zur Laufzeit herausstellt, wird eine System.InvalidCastException Ausnahme ausgelöst. Beispiel:

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

Konvertierungen sind auch zwischen einem Array eines aufgezählten Typs und einem Array des zugrunde liegenden Typs des aufgezählten Typs oder einem Array eines anderen Aufzählungstyps mit demselben zugrunde liegenden Typ vorhanden, vorausgesetzt, die Arrays haben denselben 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

In diesem Beispiel wird ein Array von Color einem Array des zugrunde liegenden Typs in und aus einem Array des ByteColorzugrunde liegenden Typs konvertiert. Die Konvertierung in ein Array von Integerist jedoch ein Fehler, da Integer es sich nicht um den zugrunde liegenden Typ von Color.

Ein Array vom Typ A() "Rang 1" hat auch eine Arraykonvertierung in die Sammlungsschnittstellentypen IList(Of B), IReadOnlyList(Of B), ICollection(Of B)IReadOnlyCollection(Of B) und IEnumerable(Of B) die in System.Collections.Generic, sofern eine der folgenden Bedingungen zutrifft:

  • A und B sind sowohl Bezugstypen als auch Typparameter, die nicht als Werttypen bekannt sind; und A weist eine Erweiterung des Bezugs, eines Arrays oder eines Typparameters auf B; oder
  • A und B sind beide Aufzählungstypen desselben zugrunde liegenden Typs oder
  • einer von A und B ist ein aufgezählter Typ, und der andere ist der zugrunde liegende Typ.

Jedes Array vom Typ A mit einem beliebigen Rang weist auch eine Arraykonvertierung in die nicht generischen Sammlungsschnittstellentypen IListICollection auf und IEnumerable befindet sich in System.Collections.

Es ist möglich, die resultierenden Schnittstellen mithilfe For Eachoder durch direktes Aufrufen der GetEnumerator Methoden zu durchlaufen. Im Fall von Rang-1-Arrays, die generische oder nicht generische Formen von IList oder ICollection, es ist auch möglich, Elemente nach Index abzurufen. Im Fall von Rang-1-Arrays, die in generische oder nicht generische Formen IListkonvertiert werden, ist es auch möglich, Elemente nach Index festzulegen, vorbehaltlich der gleichen Laufzeit-Array-Kovarianzprüfungen wie oben beschrieben. Das Verhalten aller anderen Schnittstellenmethoden ist von der VB-Sprachspezifikation nicht definiert; es liegt bei der zugrunde liegenden Laufzeit.

Werttypkonvertierungen

Ein Werttypwert kann in einen seiner Basisverweistypen oder einen Schnittstellentyp konvertiert werden, der über einen Prozess implementiert wird, der als Boxing bezeichnet wird. Wenn ein Werttypwert eingefeldt wird, wird der Wert aus dem Speicherort kopiert, an dem er sich auf den .NET Framework-Heap befindet. Ein Verweis auf diesen Speicherort im Heap wird dann zurückgegeben und kann in einer Referenztypvariable gespeichert werden. Dieser Verweis wird auch als boxierte Instanz des Werttyps bezeichnet. Die boxed instance has the same semantics as a reference type instead of a value type.

Boxed value types can be converted back to their original value type through a process called unboxing. Wenn ein Feldwerttyp entboxt wird, wird der Wert aus dem Heap an einen variablen Speicherort kopiert. Ab diesem Zeitpunkt verhält es sich so, als ob es sich um einen Werttyp handelte. Beim Aufheben des Posteingangs eines Werttyps muss der Wert ein NULL-Wert oder eine Instanz des Werttyps sein. Andernfalls wird eine System.InvalidCastException Ausnahme ausgelöst. Wenn es sich bei dem Wert um eine Instanz eines Aufzählungstyps handelt, kann dieser Wert auch in den zugrunde liegenden Typ des aufgezählten Typs oder einen anderen Aufzählungstyp mit demselben zugrunde liegenden Typ entboxt werden. Ein Nullwert wird so behandelt, als wäre er das Literal Nothing.

Um Nullwertetypen gut zu unterstützen, wird der Werttyp System.Nullable(Of T) speziell beim Boxen und Aufheben des Posteingangs behandelt. Das Boxen eines Typs Nullable(Of T) führt zu einem Feldwert des TypsT, wenn die Eigenschaft des Werts HasValue oder ein Wert Nothing istTrue, wenn die Eigenschaft des Werts HasValue lautetFalse. Das Entpacken eines Typwerts T führt zu Nullable(Of T) einer Instanz Nullable(Of T) dessen Value Eigenschaft der Boxwert und dessen HasValue Eigenschaft ist True. Der Wert kann für jeden Wert Nothing aufgehoben Nullable(Of T) werden und führt zu einem Wert, dessen HasValue Eigenschaft lautetFalse.T Da boxed value types like reference types, it is possible to create multiple references to the same value. Für die Grundtypen und Enumerationstypen ist dies irrelevant, da Instanzen dieser Typen unveränderlich sind. Das heißt, es ist nicht möglich, eine boxierte Instanz dieser Typen zu ändern, daher ist es nicht möglich, die Tatsache zu beobachten, dass mehrere Verweise auf denselben Wert vorhanden sind.

Strukturen können dagegen änderbar sein, wenn auf ihre Instanzvariablen zugegriffen werden kann oder ob die Methoden oder Eigenschaften die Instanzvariablen ändern. Wenn ein Verweis auf eine Boxstruktur verwendet wird, um die Struktur zu ändern, werden alle Verweise auf die Boxstruktur die Änderung sehen. Da dieses Ergebnis unerwartet sein kann, wird beim Eingeben eines Werts Object , der von einem Speicherort in einen anderen Feldwerttypen eingegeben wird, automatisch auf dem Heap geklont, anstatt nur deren Verweise kopiert zu haben. Beispiel:

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

Die Ausgabe des Programms ist:

Values: 0, 123
Refs: 123, 123

Die Zuordnung zum Feld der lokalen Variablen wirkt sich nicht auf das Feld der lokalen Variablen val2val1 aus, da beim Zuweisen val2des Felds Struct1 eine Kopie des Werts erstellt wurde. Im Gegensatz dazu wirkt sich die Zuordnung ref2.Value = 123 auf das Objekt aus, das sowohl als ref2 auch ref1 verweise.

Hinweis: Das Kopieren der Struktur erfolgt nicht für boxed structures typed, da System.ValueType es nicht möglich ist, verspätete Bindung von System.ValueType.

Es gibt eine Ausnahme von der Regel, die boxed value types wird bei der Zuordnung kopiert. Wenn ein Feldwerttypverweis innerhalb eines anderen Typs gespeichert wird, wird der innere Bezug nicht kopiert. Beispiel:

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

Die Ausgabe des Programms ist:

Values: 123, 123

Dies liegt daran, dass der innere Feldwert nicht kopiert wird, wenn der Wert kopiert wird. Daher haben beide und val1.Valueval2.Value einen Verweis auf denselben Feldwerttyp.

Hinweis: Die Tatsache, dass inner boxed value types nicht kopiert werden, ist eine Einschränkung des .NET-Typsystems – um sicherzustellen, dass alle inneren Boxwerttypen kopiert wurden, wenn ein Wert des Typs Object kopiert wurde, unerschwinglich teuer wäre.

Wie zuvor beschrieben, können Boxwerttypen nur auf ihren ursprünglichen Typ entboxt werden. Boxed primitive Typen werden jedoch speziell behandelt, wenn sie eingegeben werden.Object Sie können in jeden anderen Grundtyp konvertiert werden, in den sie eine Konvertierung haben. Beispiel:

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

Normalerweise konnte der Boxwert Integer5 nicht in eine Byte Variable entboxt werden. Da Integer es sich jedoch um primitive Typen handelt Byte und eine Konvertierung aufweisen, ist die Konvertierung zulässig.

Beachten Sie, dass sich das Konvertieren eines Werttyps in eine Schnittstelle von einem generischen Argument unterscheidet, das auf eine Schnittstelle beschränkt ist. Beim Zugriff auf Schnittstellenmember für einen eingeschränkten Typparameter (oder aufrufende Methoden für Object) tritt das Boxen nicht auf, wenn ein Werttyp in eine Schnittstelle konvertiert wird und auf ein Schnittstellenmember zugegriffen wird. Angenommen, eine Schnittstelle ICounter enthält eine Methode Increment , die zum Ändern eines Werts verwendet werden kann. Wenn ICounter sie als Einschränkung verwendet wird, wird die Implementierung der Increment Methode mit einem Verweis auf die Variable aufgerufen, die Increment aufgerufen wurde, nicht eine Boxkopie:

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

Der erste Aufruf von Increment ändert den Wert in der Variablen x. Dies ist nicht gleichbedeutend mit dem zweiten Aufruf von Increment, der den Wert in einer geboxten Kopie von x ändert. Die Ausgabe des Programms ist also:

0
1
1

Konvertierungen des Nullwerttyps

Ein Werttyp T kann in und aus der nullablen Version des Typs konvertiert werden. T? Die Konvertierung von T? zu T löst eine System.InvalidOperationException Ausnahme aus, wenn der zu konvertierende Wert ist Nothing. Verfügt außerdem über eine Konvertierung in einen TypS, T? wenn T eine systeminterne Konvertierung vorhanden Sist. Und wenn S es sich um einen Werttyp handelt, sind die folgenden systeminternen Konvertierungen zwischen T? und S?:

  • Eine Konvertierung derselben Klassifizierung (Verengung oder Verbreiterung) von T? zu S?.

  • Eine Konvertierung derselben Klassifizierung (Verengung oder Verbreiterung) von T zu S?.

  • Eine schmale Konvertierung von S? zu T.

Eine systeminterne Erweiterungskonvertierung ist beispielsweise von Integer? zu Long? einer systeminternen Erweiterungskonvertierung von Integer zu Long:

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

Beim Konvertieren von in T?S?, wenn der Wert des T? Werts ist Nothing, lautet der Wert von S?Nothing. Beim Konvertieren von in TS? oder T? in S, wenn der Wert von T? oder S? ist Nothing, wird eine System.InvalidCastException Ausnahme ausgelöst.

Aufgrund des Verhaltens des zugrunde liegenden Typs System.Nullable(Of T), wenn ein Nullwerttyp T? boxt, ist das Ergebnis ein Boxwert vom Typ T, nicht ein Boxwert vom Typ T?. Und umgekehrt wird der Wert beim Entpacken in einen Null-Wertetyp T?umbrochen System.Nullable(Of T)und Nothing wird in einen Nullwert des Typs T?entboxt. Beispiel:

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

Ein Nebeneffekt dieses Verhaltens besteht darin, dass ein Nullwerttyp T? alle Schnittstellen Timplementiert, da beim Konvertieren eines Werttyps in eine Schnittstelle der Typ ein Boxen erforderlich ist. Daher T? ist das Konvertierbar für alle Schnittstellen, T die konvertierbar sind. Es ist jedoch wichtig zu beachten, dass ein nullabler Werttyp T? nicht tatsächlich die Schnittstellen T für die generische Einschränkungsprüfung oder Reflexion implementiert. Beispiel:

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

Zeichenfolgenkonvertierungen

Konvertieren Char in String Ergebnisse in eine Zeichenfolge, deren erstes Zeichen der Zeichenwert ist. Das Konvertieren String in Char Ergebnisse in ein Zeichen, dessen Wert das erste Zeichen der Zeichenfolge ist. Das Konvertieren eines Arrays in CharString Ergebnisse in eine Zeichenfolge, deren Zeichen die Elemente des Arrays sind. Konvertieren String in ein Array von Char Ergebnissen in ein Array von Zeichen, deren Elemente die Zeichen der Zeichenfolge sind.

Die genauen Konvertierungen zwischen und , , , , UShort, Short, , UInteger, Integer, , LongULong, DateDecimalDoubleSingleund umgekehrt, sind über den Umfang dieser Spezifikation hinaus und sind implementierungsabhängig mit Ausnahme eines Details. SByteByteBooleanString Zeichenfolgenkonvertierungen berücksichtigen immer die aktuelle Kultur der Laufzeitumgebung. Daher müssen sie zur Laufzeit ausgeführt werden.

Erweiterungskonvertierungen

Verbreiterungskonvertierungen überlaufen niemals überlaufen, können aber zu einem Genauigkeitsverlust führen. Bei den folgenden Konvertierungen handelt es sich um Erweiterungskonvertierungen:

Identitäts-/Standardkonvertierungen

  • Von einem Typ zu sich selbst.

  • Von einem anonymen Delegattyp, der für eine Lambda-Methode neu klassifiziert wird, auf jeden Delegattyp mit einer identischen Signatur.

  • Vom Literal Nothing zu einem Typ.

Numerische Konvertierungen

  • Von Byte bis UShort, Short, UInteger, Integer, ULong, , Long, , Decimaloder SingleDouble.

  • Von SByte in Short, Integer, Long, Decimal, Single oder Double.

  • Von UShort in UInteger, Integer, ULong, Long, Decimal, Single oder Double.

  • Von Short bis Integer, Long, , Decimaloder DoubleSingle .

  • Von UInteger in ULong, Long, Decimal, Single oder Double.

  • Von Integer bis Long, Decimal, Single oder Double.

  • Von ULong in Decimal, Single oder Double.

  • Von Long bis , SingleDecimaloder Double.

  • Von Decimal in Single oder Double.

  • Von Single bis Double.

  • Vom Literal 0 zu einem Aufzählungstyp. (Hinweis. Die Konvertierung von 0 einem aufgezählten Typ wird erweitert, um Testkennzeichnungen zu vereinfachen. Wenn es sich z Values . B. um einen Aufzählungstyp mit einem Wert Onehandelt, können Sie eine Variable v vom Typ Values testen, indem (v And Values.One) = 0Sie ".)

  • Von einem Aufzählungstyp auf den zugrunde liegenden numerischen Typ oder auf einen numerischen Typ, in den der zugrunde liegende numerische Typ eine Erweiterungskonvertierung aufweist.

  • Von einem konstanten Ausdruck vom Typ ULong, , , UInteger, Integer, UShort, Short, oder ByteSByte zu einem schmaleren Typ, vorausgesetzt, der Wert des Konstantenausdrucks befindet sich innerhalb des Bereichs des ZieltypsLong. (Hinweis. Konvertierungen von UInteger oder Integer in Singleoder ULongLong in Single oder zu oder Doublezu oder SingleDecimalDouble können zu einem Verlust der Genauigkeit führen, aber niemals zu einem Verlust der Größe führen. Die anderen erweiternden numerischen Konvertierungen verlieren niemals Informationen.)

Referenzkonvertierungen

  • Von einem Verweistyp zu einem Basistyp.

  • Von einem Verweistyp auf einen Schnittstellentyp, vorausgesetzt, der Typ implementiert die Schnittstelle oder eine variantekompatible Schnittstelle.

  • Von einem Schnittstellentyp zu Object.

  • Von einem Schnittstellentyp zu einem variantenkompatiblen Schnittstellentyp.

  • Von einem Delegattyp zu einem variantenkompatiblen Delegattyp. (Hinweis. Viele andere Verweiskonvertierungen werden durch diese Regeln impliziert. Anonyme Stellvertretungen sind z. B. Referenztypen, die von System.MulticastDelegate;Arraytypen erben System.Array; anonyme Typen sind Referenztypen, die von System.Object.)

Konvertierungen anonymer Stellvertretungen

  • Von einem anonymen Delegattyp, der für eine Lambda-Methode neu klassifiziert wird, in einen größeren Delegattyp.

Arraykonvertierungen

  • Von einem Arraytyp mit einem Elementtyp SSe bis zu einem Arraytyp mit einem Elementtyp TTe, vorausgesetzt, alle folgenden Werte sind wahr:

    • S und T unterscheiden sich nur im Elementtyp.

    • Beide Se sind Te Bezugstypen oder Typparameter, die als Verweistyp bekannt sind.

    • Es ist eine Erweiterung des Verweises, eines Arrays oder einer Typparameterkonvertierung vorhanden.SeTe

  • Von einem Arraytyp S mit einem Aufzählungselementtyp Se zu einem Arraytyp mit einem Elementtyp TTe, vorausgesetzt, alle folgenden Sind wahr:

    • S und T unterscheiden sich nur im Elementtyp.

    • Te ist der zugrunde liegende Typ von Se.

  • Von einem Arraytyp S der Rangfolge 1 mit einem aufgezählten Elementtyp Se, bis System.Collections.Generic.IList(Of Te), , IReadOnlyList(Of Te), , ICollection(Of Te), IReadOnlyCollection(Of Te)und IEnumerable(Of Te), vorausgesetzt, einer der folgenden Werte ist wahr:

    • Beide Se sind Te Bezugstypen oder Typparameter, die als Bezugstyp bekannt sind, und eine Erweiterung des Bezugs, eines Arrays oder einer Typparameterkonvertierung besteht von Se zu Te; oder

    • Te ist der zugrunde liegende Typ von Se; oder

    • Te ist identisch mit Se

Werttypkonvertierungen

  • Von einem Werttyp zu einem Basistyp.

  • Von einem Werttyp zu einem Schnittstellentyp, den der Typ implementiert.

Konvertierungen des Nullwerttyps

  • Von einem Typ T zum Typ T?.

  • Von einem Typ T? zu einem Typ S?, wobei eine Erweiterung von dem Typ T in den Typ Svorhanden ist.

  • Von einem Typ T zu einem Typ S?, wobei eine Erweiterung von dem Typ T in den Typ Svorhanden ist.

  • Von einem Typ T? zu einem Schnittstellentyp, den der Typ T implementiert.

Zeichenfolgenkonvertierungen

  • Von Char bis String.

  • Von Char() bis String.

Typparameterkonvertierungen

  • Von einem Typparameter in Object.

  • Von einem Typparameter zu einer Schnittstellentypeinschränkung oder einer beliebigen Schnittstellenvariante, die mit einer Schnittstellentypeinschränkung kompatibel ist.

  • Von einem Typparameter zu einer Schnittstelle, die von einer Klasseneinschränkung implementiert wird.

  • Von einem Typparameter zu einer Schnittstellenvariante, die mit einer Schnittstelle kompatibel ist, die von einer Klasseneinschränkung implementiert wird.

  • Von einem Typparameter zu einer Klasseneinschränkung oder einem Basistyp der Klasseneinschränkung.

  • Von einem Typparameter T zu einer Typparametereinschränkung Txoder etwas Tx hat eine Erweiterungskonvertierung.

Eingrenzungskonvertierungen

Schmale Konvertierungen sind Konvertierungen, die nicht immer erfolgreich sein können, Konvertierungen, die bekanntermaßen Informationen verlieren, und Konvertierungen in Domänen von Typen, die ausreichend unterschiedlich sind, um eine schmale Schreibweise zu erzielen. Die folgenden Konvertierungen werden als schmale Konvertierungen klassifiziert:

Boolesche Konvertierungen

  • Von Boolean zu Byte, SByte, UShort, Short, UInteger, , Integer, ULong, LongDecimal, , , oder SingleDouble.

  • Von Byte, , SByte, UShort, Short, IntegerUInteger, , ULong, DecimalLong, , Singleoder Double nach Boolean.

Numerische Konvertierungen

  • Von Byte bis SByte.

  • Von SByte in Byte, UShort, UInteger oder ULong.

  • Von UShort in Byte, SByte oder Short.

  • Von Short in Byte, SByte, UShort, UInteger oder ULong.

  • Von UInteger in Byte, SByte, UShort, Short oder Integer.

  • Von Integer in Byte, SByte, UShort, Short, UInteger oder ULong.

  • Von ULong in Byte, SByte, UShort, Short, UInteger, Integer oder Long.

  • Von Long in Byte, SByte, UShort, Short, UInteger, Integer oder ULong.

  • Von Decimal in Byte, SByte, UShort, Short, UInteger, Integer, ULong oder Long.

  • Von Single bis Byte, SByte, UShort, Short, UInteger, , Integer, , ULongoder LongDecimal.

  • Von Double zu Byte, SByte, UShort, Short, UInteger, , Integer, , ULong, Long, , oder DecimalSingle.

  • Von einem numerischen Typ zu einem Aufzählungstyp.

  • Von einem Aufzählungstyp zu einem numerischen Typ weist sein zugrunde liegender numerischer Typ eine schmale Konvertierung auf.

  • Von einem Aufzählungstyp zu einem anderen Aufzählungstyp.

Referenzkonvertierungen

  • Von einem Verweistyp zu einem abgeleiteten Typ.

  • Von einem Klassentyp zu einem Schnittstellentyp, vorausgesetzt, der Klassentyp implementiert nicht den Schnittstellentyp oder eine schnittstellentypkompatible Variante.

  • Von einem Schnittstellentyp zu einem Klassentyp.

  • Von einem Schnittstellentyp zu einem anderen Schnittstellentyp, vorausgesetzt, es gibt keine Vererbungsbeziehung zwischen den beiden Typen und vorausgesetzt, sie sind nicht variantkompatibel.

Konvertierungen anonymer Stellvertretungen

  • Von einem anonymen Delegattyp, der für eine Lambda-Methode neu klassifiziert wird, in einen schmaleren Delegattyp.

Arraykonvertierungen

  • Von einem Arraytyp mit einem Elementtyp SSebis zu einem Arraytyp mit einem ElementtypTeT, vorausgesetzt, dass alle folgenden Werte zutreffen:

    • S und T unterscheiden sich nur im Elementtyp.
    • Beide Se sind Te Bezugstypen oder Typparameter, die nicht als Werttypen bekannt sind.
    • Ein schmaler Bezug, ein Array oder eine Typparameterkonvertierung ist von Se zu Te.
  • Von einem Arraytyp mit einem Elementtyp SeS bis zu einem Arraytyp mit einem aufgezählten Elementtyp TTe, vorausgesetzt, alle folgenden Sind wahr:

    • S und T unterscheiden sich nur im Elementtyp.
    • Se ist der zugrunde liegende Typ oder Te beide enumerierten Typen, die denselben zugrunde liegenden Typ aufweisen.
  • Von einem Arraytyp S der Rangfolge 1 mit einem aufgezählten Elementtyp Se, bis IList(Of Te), IReadOnlyList(Of Te), , ICollection(Of Te)IReadOnlyCollection(Of Te) und IEnumerable(Of Te), vorausgesetzt, einer der folgenden Werte ist wahr:

    • Beide Se sind Te Bezugstypen oder Typparameter, die als Bezugstyp bekannt sind, und eine schmale Bezugs-, Array- oder Typparameterkonvertierung ist von Se zu Te; oder
    • Se ist der zugrunde liegende Typ oder Tebeide enumerierten Typen, die denselben zugrunde liegenden Typ aufweisen.

Werttypkonvertierungen

  • Von einem Verweistyp bis zu einem abgeleiteten Werttyp.

  • Von einem Schnittstellentyp zu einem Werttyp, vorausgesetzt, der Werttyp implementiert den Schnittstellentyp.

Konvertierungen des Nullwerttyps

  • Von einem Typ T? zu einem Typ T.

  • Von einem Typ T? zu einem Typ S?, wobei eine schmale Konvertierung vom Typ T in den Typ Svorhanden ist.

  • Von einem Typ T zu einem Typ S?, wobei eine schmale Konvertierung vom Typ T in den Typ Svorhanden ist.

  • Von einem Typ S? zu einem Typ T, wobei eine Konvertierung vom Typ S in den Typ Tvorhanden ist.

Zeichenfolgenkonvertierungen

  • Von String bis Char.

  • Von String bis Char().

  • Von String und Boolean von Boolean bis zu String.

  • Konvertierungen zwischen String und Byte, SByte, UShort, , UIntegerShort, , Integer, , ULong, Long, Decimal, oder SingleDouble.

  • Von String und Date von Date bis zu String.

Typparameterkonvertierungen

  • Von Object zu einem Typparameter.

  • Von einem Typparameter zu einem Schnittstellentyp, vorausgesetzt, der Typparameter ist nicht auf diese Schnittstelle beschränkt oder auf eine Klasse beschränkt, die diese Schnittstelle implementiert.

  • Von einem Schnittstellentyp zu einem Typparameter.

  • Von einem Typparameter zu einem abgeleiteten Typ einer Klasseneinschränkung.

  • Von einem Typparameter T zu einer Typparametereinschränkung Tx hat eine Schmalungskonvertierung.

Typparameterkonvertierungen

Die Konvertierungen von Typparametern werden durch die Einschränkungen bestimmt( falls vorhanden), die sie enthalten. Ein Typparameter T kann immer in sich, in und von und von Objectjedem Beliebigen Schnittstellentyp konvertiert werden. Beachten Sie, dass es sich bei dem Typ T bei der Laufzeit um einen Werttyp handelt, die Konvertierung von TObject oder einem Schnittstellentyp eine Boxkonvertierung und konvertierung von Object oder einem Schnittstellentyp T ist eine Unboxing-Konvertierung. Ein Typparameter mit einer Klasseneinschränkung C definiert zusätzliche Konvertierungen vom Typparameter in C die Basisklassen und umgekehrt. Ein Typparameter T mit einer Typparametereinschränkung Tx definiert eine Konvertierung in Tx und alle Tx Konvertierungen.

Ein Array, dessen Elementtyp ein Typparameter mit einer Schnittstelleneinschränkung I ist, weist dieselben kovarianten Arraykonvertierungen wie ein Array auf, dessen Elementtyp festgelegt ist I, vorausgesetzt, der Typparameter verfügt auch über eine Class Einschränkung oder Klasseneinschränkung (da nur Referenzarrayelementtypen kovariant sein können). Ein Array, dessen Elementtyp ein Typparameter mit einer Klasseneinschränkung C ist, weist die gleichen kovarianten Arraykonvertierungen wie ein Array auf, dessen Elementtyp lautet C.

Die oben genannten Konvertierungsregeln lassen keine Konvertierungen von nicht eingeschränkten Typparametern in Nicht-Schnittstellentypen zu, was überraschend sein kann. Der Grund dafür ist, Verwirrung über die Semantik solcher Konvertierungen zu vermeiden. Betrachten Sie beispielsweise die folgende Deklaration:

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

Wenn die Umwandlung von T "to Integer " zulässig wäre, könnte man leicht erwarten, dass X(Of Integer).F(7) dies zurückgegeben 7Lwürde. Dies wäre jedoch nicht der Fehler, da numerische Konvertierungen nur berücksichtigt werden, wenn die Typen zur Kompilierungszeit als numerisch bekannt sind. Um die Semantik klar zu machen, muss stattdessen das obige Beispiel geschrieben werden:

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

User-Defined Konvertierungen

Systeminterne Konvertierungen sind Konvertierungen , die von der Sprache definiert werden (d. h. in dieser Spezifikation aufgeführt), während benutzerdefinierte Konvertierungen durch Überladung des CType Operators definiert werden. Wenn beim Konvertieren zwischen Typen keine systeminternen Konvertierungen anwendbar sind, werden benutzerdefinierte Konvertierungen berücksichtigt. Wenn eine benutzerdefinierte Konvertierung vorhanden ist, die für die Quell- und Zieltypen spezifisch ist, wird die benutzerdefinierte Konvertierung verwendet. Andernfalls ergibt sich ein Kompilierungszeitfehler. Die spezifischste Konvertierung ist der Operand, dessen Operand dem Quelltyp am nächsten kommt und dessen Ergebnistyp dem Zieltyp am nächsten kommt. Bei der Bestimmung der zu verwendenden benutzerdefinierten Konvertierung wird die spezifische Erweiterungskonvertierung verwendet; Wenn keine Erweiterungskonvertierung spezifisch ist, wird die spezifische Schmalungskonvertierung verwendet. Wenn keine spezifische Einschränkungskonvertierung vorhanden ist, ist die Konvertierung nicht definiert, und ein Kompilierungszeitfehler tritt auf.

In den folgenden Abschnitten wird beschrieben, wie die spezifischen Konvertierungen bestimmt werden. Sie verwenden die folgenden Begriffe:

Wenn eine systeminterne Erweiterungskonvertierung von einem Typ A zu einem Typ Bvorhanden ist und weder AB Schnittstellen noch Schnittstellen sind, A wird sie vonBund BumfasstA.

Der umfassendste Typ in einer Gruppe von Typen ist der einzige Typ, der alle anderen Typen in der Gruppe umfasst. Wenn kein einzelner Typ alle anderen Typen umfasst, weist der Satz keinen umfassendsten Typ auf. Intuitiv gesehen ist der umfassendste Typ der Gruppe der "größte" Typ - der einen Typ, in den jeder der anderen Typen durch eine Erweiterungskonvertierung konvertiert werden kann.

Der umfassendste Typ in einer Gruppe von Typen ist der typ, der von allen anderen Typen in der Gruppe umfasst wird. Wenn kein einzelner Typ von allen anderen Typen umfasst, hat der Satz keinen am meisten eingeschlossenen Typ. Intuitiv gesehen ist der am meisten eingeschlossene Typ der "kleinste" Typ in der Gruppe - der eine Typ, der durch eine schmale Konvertierung in jeden der anderen Typen konvertiert werden kann.

Beim Sammeln der benutzerdefinierten Konvertierungen für einen Typ T?werden stattdessen die benutzerdefinierten Konvertierungsoperatoren verwendet, die von T ihnen definiert werden. Wenn der Typ, in den konvertiert wird, auch ein Nullwerttyp ist, werden alle Tbenutzerdefinierten Konvertierungsoperatoren, die nur nicht nullable Werttypen umfassen, aufgehoben. Ein Konvertierungsoperator von T zu "In" wird aufgehoben, um eine Konvertierung von T? zu S? zu sein, und wird bei Bedarf ausgewertet, indem T?Ter in , falls erforderlich, den benutzerdefinierten Konvertierungsoperator TS auswertet und dann in , falls erforderlich, konvertiert.SS?S Wenn der zu konvertierende NothingWert jedoch ist, wird ein aufgehobener Konvertierungsoperator direkt in einen Wert vom Nothing Typ "As S?" konvertiert. Beispiel:

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

Bei der Auflösung von Konvertierungen werden benutzerdefinierte Konvertierungsoperatoren immer gegenüber aufgehobenen Konvertierungsoperatoren bevorzugt. Beispiel:

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

Zur Laufzeit kann die Auswertung einer benutzerdefinierten Konvertierung bis zu drei Schritte umfassen:

  1. Zunächst wird der Wert aus dem Quelltyp mithilfe einer systeminternen Konvertierung in den Operandentyp konvertiert.

  2. Anschließend wird die benutzerdefinierte Konvertierung aufgerufen.

  3. Schließlich wird das Ergebnis der benutzerdefinierten Konvertierung bei Bedarf mithilfe einer systeminternen Konvertierung in den Zieltyp konvertiert.

Es ist wichtig zu beachten, dass die Auswertung einer benutzerdefinierten Konvertierung niemals mehr als einen benutzerdefinierten Konvertierungsoperator umfasst.

Die spezifischste Verbreiterungskonvertierung

Die Ermittlung des spezifisch benutzerdefinierten Erweiterungskonvertierungsoperators zwischen zwei Typen erfolgt mithilfe der folgenden Schritte:

  1. Zunächst werden alle Kandidatenkonvertierungsoperatoren gesammelt. Die Kandidatenkonvertierungsoperatoren sind alle benutzerdefinierten Verbreiterungsoperatoren im Quelltyp und alle benutzerdefinierten Erweiterungskonvertierungsoperatoren im Zieltyp.

  2. Anschließend werden alle nicht anwendbaren Konvertierungsoperatoren aus der Gruppe entfernt. Ein Konvertierungsoperator gilt für einen Quelltyp und Zieltyp, wenn ein systeminterner Erweiterungskonvertierungsoperator vom Quelltyp auf den Operandentyp vorhanden ist und ein systeminterner Verbreiterungskonvertierungsoperator vom Ergebnis des Operators auf den Zieltyp vorhanden ist. Wenn keine anwendbaren Konvertierungsoperatoren vorhanden sind, gibt es keine spezifische Erweiterungskonvertierung.

  3. Anschließend wird der spezifischste Quelltyp der entsprechenden Konvertierungsoperatoren bestimmt:

    • Wenn eine der Konvertierungsoperatoren direkt vom Quelltyp konvertiert wird, ist der Quelltyp der spezifischste Quelltyp.

    • Andernfalls ist der spezifischste Quelltyp der am meisten eingeschlossene Typ in der kombinierten Gruppe von Quelltypen der Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Erweiterungskonvertierung.

  4. Anschließend wird der spezifischste Zieltyp der anwendbaren Konvertierungsoperatoren bestimmt:

    • Wenn eine der Konvertierungsoperatoren direkt in den Zieltyp konvertiert wird, ist der Zieltyp der spezifischste Zieltyp.

    • Andernfalls ist der spezifischste Zieltyp der umfassendste Typ in der kombinierten Gruppe von Zieltypen der Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Erweiterungskonvertierung.

  5. Wenn dann genau ein Konvertierungsoperator vom spezifischsten Quelltyp in den spezifischsten Zieltyp konvertiert wird, ist dies der spezifischste Konvertierungsoperator. Wenn mehr als ein solcher Operator vorhanden ist, gibt es keine spezifische Erweiterungskonvertierung.

Die spezifischste Verengungskonvertierung

Die Ermittlung des spezifischen benutzerdefinierten Verengungsoperators zwischen zwei Typen erfolgt mithilfe der folgenden Schritte:

  1. Zunächst werden alle Kandidatenkonvertierungsoperatoren gesammelt. Die Kandidatenkonvertierungsoperatoren sind alle benutzerdefinierten Konvertierungsoperatoren im Quelltyp und alle benutzerdefinierten Konvertierungsoperatoren im Zieltyp.

  2. Anschließend werden alle nicht anwendbaren Konvertierungsoperatoren aus der Gruppe entfernt. Ein Konvertierungsoperator gilt für einen Quelltyp und Zieltyp, wenn ein systeminterner Konvertierungsoperator vom Quelltyp in den Operandentyp vorhanden ist und ein systeminterner Konvertierungsoperator vom Ergebnis des Operators in den Zieltyp vorhanden ist. Wenn keine anwendbaren Konvertierungsoperatoren vorhanden sind, gibt es keine spezifische Schmalungskonvertierung.

  3. Anschließend wird der spezifischste Quelltyp der entsprechenden Konvertierungsoperatoren bestimmt:

    • Wenn eine der Konvertierungsoperatoren direkt vom Quelltyp konvertiert wird, ist der Quelltyp der spezifischste Quelltyp.

    • Andernfalls, wenn einer der Konvertierungsoperatoren aus Typen konvertiert wird, die den Quelltyp umfassen, ist der spezifischste Quelltyp der am meisten eingeschlossene Typ in der kombinierten Gruppe von Quelltypen dieser Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Verengungskonvertierung.

    • Andernfalls ist der spezifischste Quelltyp der umfassendste Typ in der kombinierten Gruppe von Quelltypen der Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Verengungskonvertierung.

  4. Anschließend wird der spezifischste Zieltyp der anwendbaren Konvertierungsoperatoren bestimmt:

    • Wenn eine der Konvertierungsoperatoren direkt in den Zieltyp konvertiert wird, ist der Zieltyp der spezifischste Zieltyp.

    • Andernfalls, wenn eines der Konvertierungsoperatoren in Typen konvertiert wird, die vom Zieltyp eingeschlossen sind, ist der spezifischste Zieltyp der am meisten umfassende Typ in der kombinierten Gruppe von Quelltypen dieser Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Verengungskonvertierung.

    • Andernfalls ist der spezifischste Zieltyp der am meisten eingeschlossene Typ in der kombinierten Gruppe von Zieltypen der Konvertierungsoperatoren. Wenn kein umfassendster Typ gefunden werden kann, gibt es keine spezifische Verengungskonvertierung.

  5. Wenn dann genau ein Konvertierungsoperator vom spezifischsten Quelltyp in den spezifischsten Zieltyp konvertiert wird, ist dies der spezifischste Konvertierungsoperator. Wenn mehr als ein solcher Operator vorhanden ist, gibt es keine spezifische Verengungskonvertierung.

Native Konvertierungen

Mehrere der Konvertierungen werden als systemeigene Konvertierungen klassifiziert, da sie von .NET Framework nativ unterstützt werden. Diese Konvertierungen sind solche, die durch die Verwendung der DirectCast Operatoren und TryCast Konvertierungsoperatoren sowie andere spezielle Verhaltensweisen optimiert werden können. Die als systemeigenen Konvertierungen klassifizierten Konvertierungen sind: Identitätskonvertierungen, Standardkonvertierungen, Referenzkonvertierungen, Arraykonvertierungen, Werttypkonvertierungen und Typparameterkonvertierungen.

Dominanter Typ

Angesichts einer Reihe von Typen ist es häufig erforderlich, in Situationen wie typinferenz, um den dominanten Typ des Satzes zu bestimmen. Der dominante Typ einer Gruppe von Typen wird bestimmt, indem zuerst alle Typen entfernt werden, in die mindestens ein anderer Typ keine implizite Konvertierung aufweist. Wenn an diesem Punkt keine Typen vorhanden sind, gibt es keinen dominanten Typ. Der dominante Typ wird dann am meisten von den verbleibenden Typen erfasst. Wenn mehr als ein Typ vorhanden ist, der am meisten umfasst ist, gibt es keinen dominanten Typ.