Problembehandlung bei Datentypen (Visual Basic)

Auf dieser Seite sind einige häufige Probleme aufgeführt, die beim Ausführen von Vorgängen für systeminterne Datentypen auftreten können.

Gleitkommaausdrücke werden beim Vergleich nicht als gleich ausgewertet

Wenn Sie mit Gleitkommazahlen (Single-Datentyp und Double-Datentyp) arbeiten, denken Sie daran, dass sie als binäre Brüche gespeichert werden. Dies bedeutet, dass sie keine genaue Darstellung einer Menge enthalten können, die kein binärer Bruch ist (in der Form k/ (2 ^ n), wobei k und n ganze Zahlen sind). Beispielsweise können 0,5 (= 1/2) und 0,3125 (= 5/16) als genaue Werte gespeichert werden, während 0,2 (= 1/5) und 0,3 (= 3/10) nur Annäherungen sein können.

Aufgrund dieser Ungenauigkeit können Sie sich nicht auf exakte Ergebnisse verlassen, wenn Sie mit Gleitkommawerten arbeiten. Insbesondere können zwei theoretisch identische Werte leicht unterschiedliche Darstellungen aufweisen.

So vergleichen Sie Gleitkommamengen
1. Berechnen Sie den absoluten Wert ihrer Differenz, indem Sie die Abs-Methode der Math-Klasse im System-Namespace verwenden.
2. Legen Sie eine maximal zulässige Differenz fest, sodass Sie die beiden Mengen für praktische Zwecke als identisch betrachten können, wenn ihre Differenz diesen Wert nicht überschreitet.
3. Vergleichen Sie den absoluten Wert der Differenz mit der zulässigen Differenz.

Im folgenden Beispiel wird sowohl ein falscher als auch ein korrekter Vergleich von zwei Double-Werten veranschaulicht.

Dim oneThird As Double = 1.0 / 3.0
Dim pointThrees As Double = 0.333333333333333

' The following comparison does not indicate equality.
Dim exactlyEqual As Boolean = (oneThird = pointThrees)

' The following comparison indicates equality.
Dim closeEnough As Double = 0.000000000000001
Dim absoluteDifference As Double = Math.Abs(oneThird - pointThrees)
Dim practicallyEqual As Boolean = (absoluteDifference < closeEnough)

MsgBox("1.0 / 3.0 is represented as " & oneThird.ToString("G17") &
    vbCrLf & "0.333333333333333 is represented as " &
    pointThrees.ToString("G17") &
    vbCrLf & "Exact comparison generates " & CStr(exactlyEqual) &
    vbCrLf & "Acceptable difference comparison generates " &
    CStr(practicallyEqual))

Im vorherigen Beispiel wird die ToString-Methode der Double-Struktur eingesetzt, damit eine höhere Genauigkeit angegeben werden kann als vom CStr-Schlüsselwort verwendet wird. Der Standardwert ist 15 Ziffern, wird aber durch das Format „G17“ auf 17 Ziffern erweitert.

Mod-Operator gibt kein genaues Ergebnis zurück

Aufgrund der Ungenauigkeit des Gleitkommaspeichers kann der Mod-Operator ein unerwartetes Ergebnis zurückgeben, wenn mindestens einer der Operanden eine Gleitkommazahl ist.

Der Dezimaldatentyp verwendet keine Gleitkommadarstellung. Viele Zahlen, die in Single und Double ungenau sind, sind in Decimal genau (z. B. 0,2 und 0,3). Obwohl Arithmetik in Decimal langsamer ist als im Gleitkommaformat, können sich die Leistungseinbußen lohnen, um eine bessere Genauigkeit zu erreichen.

So finden Sie den ganzzahligen Rest von Gleitkommamengen
1. Deklarieren Sie Variablen alsDecimal.
2. Verwenden Sie das Literal-Typzeichen D, um für Literale den Decimal-Datentyp zu erzwingen, falls deren Werte für den Long-Datentyp zu groß sind.

Im folgenden Beispiel wird die potenzielle Ungenauigkeit von Gleitkommaoperanden veranschaulicht.

Dim two As Double = 2.0
Dim zeroPointTwo As Double = 0.2
Dim quotient As Double = two / zeroPointTwo
Dim doubleRemainder As Double = two Mod zeroPointTwo

MsgBox("2.0 is represented as " & two.ToString("G17") &
    vbCrLf & "0.2 is represented as " & zeroPointTwo.ToString("G17") &
    vbCrLf & "2.0 / 0.2 generates " & quotient.ToString("G17") &
    vbCrLf & "2.0 Mod 0.2 generates " &
    doubleRemainder.ToString("G17"))

Dim decimalRemainder As Decimal = 2D Mod 0.2D
MsgBox("2.0D Mod 0.2D generates " & CStr(decimalRemainder))

Im vorherigen Beispiel wird die ToString-Methode der Double-Struktur eingesetzt, damit eine höhere Genauigkeit angegeben werden kann als vom CStr-Schlüsselwort verwendet wird. Der Standardwert ist 15 Ziffern, wird aber durch das Format „G17“ auf 17 Ziffern erweitert.

Da zeroPointTwo den Double-Datentyp aufweist, ist der zugehörige Wert für 0,2 ein sich unendlich wiederholender binärer Bruch mit einem gespeicherten Wert von 0,20000000000000001. Die Division von 2,0 durch diese Menge ergibt 9,9999999999999995 mit einem Rest von 0,19999999999999991.

Im Ausdruck für decimalRemainder erzwingt das Literal-Typzeichen D für beide Operanden den Decimal-Datentyp, sodass 0,2 genau dargestellt wird. Somit ergibt der Mod-Operator den erwarteten Rest von 0,0.

Beachten Sie, dass es nicht ausreicht, decimalRemainder als Decimal zu deklarieren. Sie müssen auch für die Literale den Decimal-Datentyp erzwingen, da sie ansonsten standardmäßig Double verwenden und decimalRemainder denselben ungenauen Wert wie doubleRemainder erhält.

Boolescher Typ wird nicht genau in numerischen Typ konvertiert

Werte des booleschen Datentyps werden nicht als Zahlen gespeichert, und es ist nicht beabsichtigt, dass die gespeicherten Werte eine numerische Entsprechung aufweisen. Aus Gründen der Kompatibilität mit früheren Versionen stellt Visual Basic Konvertierungsschlüsselwörter (CType-Funktion, CBool, CInt usw.) bereit, die eine Konvertierung zwischen Boolean und numerischen Typen durchführen. Andere Sprachen führen diese Konvertierungen jedoch manchmal anders aus, ebenso wie die .NET Framework-Methoden.

Sie sollten niemals Code schreiben, der auf entsprechenden numerischen Werten für True und False basiert. Nach Möglichkeit sollten Sie die Nutzung von Boolean-Variablen auf die für sie vorgesehenen logischen Werte beschränken. Wenn Sie Boolean- und numerische Werte kombinieren müssen, stellen Sie sicher, dass Sie die Auswirkungen der ausgewählten Konvertierungsmethode kennen.

Konvertierung in Visual Basic

Wenn Sie die Konvertierungsschlüsselwörter CType oder CBool verwenden, um numerische Datentypen in Boolean zu konvertieren, wird 0 als False und alle anderen Werte als True ausgewertet. Wenn Sie Boolean-Werte mithilfe der Konvertierungsschlüsselwörter in numerische Typen konvertieren, wird False als 0 und True als -1 ausgewertet.

Konvertierung im Framework

Die ToInt32-Methode der Convert-Klasse im System-Namespace konvertiert True in +1.

Wenn Sie einen Boolean-Wert in einen numerischen Datentyp konvertieren müssen, achten Sie darauf, welche Konvertierungsmethode Sie verwenden.

Zeichenliteral generiert Compilerfehler

Wenn keine Typzeichen vorhanden sind, geht Visual Basic von Standarddatentypen für Literale aus. Der Standardtyp für ein Zeichenliteral – in Anführungszeichen (" ") eingeschlossen – ist String.

Der String-Datentyp wird nicht auf den Char-Datentyp erweitert. Wenn Sie einer Char-Variablen ein Literal zuweisen möchten, müssen Sie daher entweder eine einschränkende Konvertierung vornehmen oder für das Literal den Char-Typ erzwingen.

So erstellen Sie ein Char-Literal, das einer Variablen oder einer Konstanten zugewiesen werden soll
1. Deklarieren Sie die Variable oder Konstante als Char.
2. Schließen Sie den Zeichenwert in Anführungszeichen (" ") ein.
3. Fügen Sie nach dem schließenden doppelten Anführungszeichen das Literaltypzeichen C hinzu, um für das Literal den Char-Datentyp zu erzwingen. Dies ist erforderlich, wenn die Typüberprüfungsoption (Option Strict-Anweisung) On lautet, und es empfiehlt sich auch in jedem anderen Fall.

Im folgenden Beispiel werden sowohl erfolglose als auch erfolgreiche Zuweisungen eines Literals zu einer Char-Variablen veranschaulicht.

Dim charVar As Char
' The following statement attempts to convert a String literal to Char.
' Because Option Strict is On, it generates a compiler error.
charVar = "Z"
' The following statement succeeds because it specifies a Char literal.
charVar = "Z"c
' The following statement succeeds because it converts String to Char.
charVar = CChar("Z")

Es besteht immer ein Risiko bei der Verwendung der einschränkenden Konvertierung, da sie zur Laufzeit fehlschlagen kann. Beispielsweise kann eine Konvertierung von String in Char fehlschlagen, wenn der String-Wert mehrere Zeichen enthält. Daher empfiehlt es sich, bei der Programmierung das C-Typzeichen zu verwenden.

Fehler bei der Zeichenfolgenkonvertierung zur Laufzeit

Der Zeichenfolgendatentyp ist an sehr wenigen erweiternden Konvertierungen beteiligt. String wird nur auf sich selbst und auf Object erweitert, und nur Char und Char() (ein Char-Array) werden auf String erweitert. Dies liegt daran, dass String-Variablen und -Konstanten Werte enthalten können, die andere Datentypen nicht enthalten können.

Wenn die Option für die Typüberprüfung (Option Strict-Anweisung) auf On festgelegt ist, lässt der Compiler keine impliziten einschränkenden Konvertierungen zu. Dies gilt auch für diejenigen, an denen der String-Datentyp beteiligt ist. Ihr Code kann weiterhin Konvertierungsschlüssel wie CStr und die CType-Funktion verwenden, die das .NET Framework anweisen, die Konvertierung zu versuchen.

Hinweis

Der Fehler bei der einschränkenden Konvertierung wird für Konvertierungen der Elemente in einer For Each…Next-Auflistung in die Schleifensteuerungsvariable unterdrückt. Weitere Informationen und Beispiele finden Sie im Abschnitt „Einschränkende Konvertierungen“ unter For Each...Next-Anweisung.

Schutz der einschränkenden Konvertierung

Der Nachteil von einschränkenden Konvertierungen besteht darin, dass sie zur Laufzeit fehlschlagen können. Wenn eine String-Variable beispielsweise einen anderen Wert als TRUE oder FALSE enthält, kann sie nicht in Boolean konvertiert werden. Wenn sie Interpunktionszeichen enthält, schlägt die Konvertierung in einen beliebigen numerischen Typ fehl. Wenn Sie nicht genau wissen, ob Ihre String-Variable immer Werte enthält, die der Zieltyp akzeptieren kann, sollten Sie keine Konvertierung versuchen.

Wenn Sie von String in einen anderen Datentyp konvertieren müssen, besteht die sicherste Prozedur darin, die versuchte Konvertierung in die Try...Catch...Finally-Anweisung einzuschließen. Auf diese Weise können Sie einen Laufzeitfehler behandeln.

Zeichenarrays

Ein einzelnes Char-Element und ein Array aus Char-Elementen können beide auf String erweitert werden. String kann jedoch nicht auf Char() erweitert werden. Um einen String-Wert in ein Char-Array zu konvertieren, können Sie die ToCharArray-Methode der System.String-Klasse verwenden.

Bedeutungslose Werte

Im Allgemeinen sind String-Werte in anderen Datentypen nicht sinnvoll, und die Konvertierung ist hochgradig gefährlich. Nach Möglichkeit sollten Sie die Nutzung von String-Variablen auf die für sie vorgesehenen Zeichensequenzen beschränken. Sie sollten niemals Code schreiben, der auf entsprechenden Werten in anderen Typen basiert.

Siehe auch