Dépannage des types de données (Visual Basic)

Cette page liste certains problèmes courants qui peuvent se produire quand vous effectuez des opérations sur des types de données intrinsèques.

Les expressions à virgule flottante comparées ne sont pas égales

Si vous utilisez des nombres à virgule flottante (types de données Single et Double), n’oubliez pas qu’ils sont stockés en tant que fractions binaires. Cela signifie qu’ils ne peuvent pas contenir une représentation exacte d’une quantité qui n’est pas une fraction binaire (de la forme k / (2 ^ n) où k et n sont des entiers). Par exemple, 0,5 (= 1/2) et 0,3125 (= 5/16) peuvent être considérés comme des valeurs précises, tandis que 0,2 (= 1/5) et 0,3 (= 3/10) peuvent être uniquement des approximations.

En raison de cette imprécision, vous ne pouvez pas compter obtenir des résultats exacts quand vous utilisez des valeurs à virgule flottante. En particulier, deux valeurs théoriquement égales peuvent avoir des représentations légèrement différentes.

Pour comparer des quantités à virgule flottante
1. Calculez la valeur absolue de leur différence en utilisant la méthode Abs de la classe Math dans l’espace de noms System.
2. Déterminez une différence maximale acceptable. Si la différence entre deux quantités ne dépasse pas cette limite, considérez-les comme égales à des fins pratiques.
3. Comparez la valeur absolue de la différence à la différence acceptable.

L’exemple suivant illustre une comparaison incorrecte et une comparaison correcte de deux valeurs Double.

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))

L’exemple précédent utilise la méthode ToString de la structure Double, ce qui permet de spécifier une meilleure précision que celle utilisée par le mot clé CStr. La valeur par défaut est de 15 chiffres, mais le format « G17 » l’étend à 17 chiffres.

L’opérateur Mod ne retourne pas de résultat précis

En raison de l’imprécision du stockage des valeurs à virgule flottante, l’opérateur Mod peut retourner un résultat inattendu quand au moins l’un des opérandes est à virgule flottante.

Le type de données Decimal n’utilise pas de représentation à virgule flottante. De nombreux nombres qui sont inexacts dans les types de données Single et Double sont exacts dans le type Decimal (par exemple, 0,2 et 0,3). Bien que les calculs arithmétiques soient plus lents dans le type de données Decimal que dans le type Virgule flottante, il peut être utile de diminuer les performances pour obtenir une meilleure précision.

Pour trouver le reste entier des quantités à virgule flottante
1. Déclarez les variables en tant que Decimal.
2. Utilisez le caractère de type littéral D pour forcer les littéraux à prendre le type Decimal, au cas où leurs valeurs seraient trop importantes pour le type de données Long.

L’exemple suivant illustre l’imprécision potentielle des opérandes à virgule flottante.

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))

L’exemple précédent utilise la méthode ToString de la structure Double, ce qui permet de spécifier une meilleure précision que celle utilisée par le mot clé CStr. La valeur par défaut est de 15 chiffres, mais le format « G17 » l’étend à 17 chiffres.

Étant donné que zeroPointTwo est un type Double, sa valeur pour 0,2 est une fraction binaire se répétant à l’infini avec une valeur stockée de 0,20000000000000001. En divisant 2,0 par cette quantité, vous obtenez 9,9999999999999995 avec un reste de 0,19999999999999991.

Dans l’expression pour decimalRemainder, le caractère de type littéral D force les deux opérandes à prendre le type Decimal, et 0,2 a une représentation précise. Par conséquent, l’opérateur Mod génère le reste attendu de 0,0.

Notez qu’il ne suffit pas de déclarer decimalRemainder en tant que type Decimal. Vous devez également forcer les littéraux à prendre le type Decimal. Sinon, ils utilisent le type Double par défaut et decimalRemainder reçoit la même valeur inexacte que doubleRemainder.

Le type booléen n’est pas converti avec précision en type numérique

Les valeurs de type de données booléen ne sont pas stockées sous forme de nombres, et les valeurs stockées ne sont pas destinées à être équivalentes à des nombres. Pour assurer la compatibilité avec les versions antérieures, Visual Basic fournit des mots clés de conversion (fonction CType, CBool, CInt, etc.) pour convertir les types Boolean en types numériques et vice versa. Toutefois, d’autres langages ainsi que les méthodes .NET Framework peuvent parfois effectuer ces conversions différemment.

Vous ne devez jamais écrire de code qui repose sur des valeurs numériques équivalentes pour True et False. Dans la mesure du possible, vous devez limiter l’utilisation des variables Boolean aux valeurs logiques pour lesquelles elles sont conçues. Si vous devez mélanger des valeurs Boolean et des valeurs numériques, veillez à bien comprendre la méthode de conversion que vous sélectionnez.

Conversion en Visual Basic

Quand vous utilisez le mot clé de conversion CType ou CBool pour convertir des types de données numériques en Boolean, 0 devient False et toutes les autres valeurs deviennent True. Quand vous convertissez des valeurs Boolean en types numériques à l’aide des mots clés de conversion, False devient 0 et True devient -1.

Conversion dans le framework

La méthode ToInt32 de la classe Convert dans l’espace de noms System convertit True en +1.

Si vous devez convertir une valeur Boolean en type de données numérique, faites attention à la méthode de conversion que vous utilisez.

Un littéral de caractère génère une erreur de compilation

En l’absence de caractères de type, Visual Basic part du principe que les littéraux sont du type de données par défaut. Le type par défaut d’un littéral de caractère, placé entre guillemets (" "), est String.

Le type de données String ne s’étend pas au type de données caractères. Cela signifie que si vous souhaitez affecter un littéral à une variable Char, vous devez soit effectuer une conversion restrictive, soit forcer le littéral à prendre le type Char.

Pour créer un littéral Char à affecter à une variable ou à une constante
1. Déclarez la variable ou la constante en tant que Char.
2. Placez la valeur de caractère entre guillemets (" ").
3. Faites suivre le guillemet double fermant du caractère de type littéral C pour forcer le littéral à prendre le type Char. Cela est nécessaire si le commutateur de contrôle de type (instruction Option Strict) est On. Il est de toute façon souhaitable dans tous les cas.

L’exemple suivant illustre les affectations réussies ou non d’un littéral à une variable Char.

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")

L’utilisation de conversions restrictives comporte toujours un risque, car elles peuvent échouer au moment de l’exécution. Par exemple, une conversion de String en Char peut échouer si la valeur String contient plusieurs caractères. Il est donc préférable d’utiliser le caractère de type C.

La conversion de chaîne échoue au moment de l’exécution

Le type de données String participe à très peu de conversions étendues. Le type String s’étend uniquement à lui-même et à Object, et seuls Char et Char() (un tableau Char) s’étendent à String. Cela est dû au fait que les variables et constantes String peuvent contenir des valeurs que d’autres types de données ne peuvent pas contenir.

Quand le commutateur de contrôle de type (instruction Option Strict) est On, le compilateur interdit toutes les conversions restrictives implicites. Cela inclut celles qui impliquent le type String. Votre code peut toujours utiliser des mots clés de conversion tels que CStr et la fonction CType qui indiquent au .NET Framework de tenter la conversion.

Notes

L’erreur de conversion restrictive est supprimée pour les conversions des éléments d’une collection For Each…Next en variable de contrôle de boucle. Pour obtenir plus d’informations et des d’exemples, consultez la section « Conversions restrictives » dans For Each...Next, instruction.

Protection des conversions restrictives

Les conversions restrictives ont comme inconvénient de pouvoir échouer au moment de l’exécution. Par exemple, si une variable String contient autre chose que « True » ou « False », elle ne peut pas être convertie en Boolean. Si elle contient des caractères de ponctuation, la conversion en type numérique échoue. Il est donc déconseillé de tenter une conversion, sauf si vous savez que votre variable String contient toujours des valeurs que le type de destination peut accepter.

Pour convertir une valeur String en autre type de données, la procédure la plus sûre consiste à inclure la tentative de conversion dans l’instruction Try...Catch...Finally. Vous pourrez ainsi gérer les échecs d’exécution.

Tableaux de caractères

Un seul Char et un tableau d’éléments Char s’étendent tous deux à String. Toutefois, String ne s’étend pas à Char(). Pour convertir une valeur String en tableau Char, vous pouvez utiliser la méthode ToCharArray de la classe System.String.

Valeurs sans signification

En général, les valeurs String ne sont pas significatives dans d’autres types de données, et la conversion est hautement artificielle et dangereuse. Dans la mesure du possible, vous devez limiter l’utilisation des variables String aux séquences de caractères pour lesquelles elles sont conçues. Vous ne devez jamais écrire de code qui repose sur des valeurs équivalentes dans d’autres types.

Voir aussi