Устранение неполадок, связанных с типами данных (Visual Basic)

На этой странице перечислены некоторые распространенные проблемы, которые могут возникнуть при выполнении операций с встроенными типами данных.

выражения Floating-Point не сравниваются как равные

При работе с числами с плавающей запятой (одинарные и двойные) следует помнить, что они хранятся в виде двоичных дробей. Это означает, что они не могут содержать точное представление количества, не представляющее двоичную дробь (формы k / (2 ^ n), где k и n являются целыми числами). Например, 0,5 (= 1/2) и 0,3125 (= 5/16) могут содержаться в виде точных значений, тогда как 0,2 (= 1/5) и 0,3 (= 3/10) могут быть только приближенными.

Из-за такой точности нельзя полагаться на точные результаты при работе со значениями с плавающей запятой. В частности, два теоретически равных значения могут иметь несколько разные представления.

Сравнение количества с плавающей запятой
1. Вычислите абсолютное значение их разницы с помощью Abs метода Math класса в System пространстве имен.
2. Определите допустимую максимальную разницу, чтобы вы могли считать эти два количества равными для практических целей, если их разница не больше.
3. Сравните абсолютное значение разницы с допустимой разницей.

В следующем примере демонстрируется неправильное и правильное сравнение двух 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))

В предыдущем примере используется ToString метод Double структуры, который позволяет указать более высокую точность, чем CStr использует ключевое слово. Значение по умолчанию — 15 цифр, но формат "G17" расширяет его до 17 цифр.

Оператор Mod не возвращает точный результат

Из-за отсутствия данных в хранилище с плавающей запятой оператор Mod может возвращать непредвиденный результат, если хотя бы один из операндов является плавающей запятой.

Тип данных Decimal не использует представление с плавающей запятой. Многие числа, которые являются неточными и SingleDouble точными в Decimal (например, 0,2 и 0,3). Хотя арифметика выполняется медленнее Decimal , чем в с плавающей запятой, для достижения лучшей точности может потребоваться снижение производительности.

Поиск целочисленного остатка количества с плавающей запятой
1. Объявите переменные как Decimal.
2. Используйте символ D литерального типа, чтобы принудительно использовать Decimalлитералы в , если их значения слишком велики для Long типа данных.

В следующем примере демонстрируется потенциальная нетка операндов с плавающей запятой.

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

В предыдущем примере используется ToString метод Double структуры, который позволяет указать более высокую точность, чем CStr использует ключевое слово. Значение по умолчанию — 15 цифр, но формат "G17" расширяет его до 17 цифр.

Поскольку zeroPointTwo имеет значение Double, его значение для 0,2 является бесконечно повторяющейся двоичной дроби с сохраненным значением 0,2000000000000001. Деление 2,0 на это количество дает 9,99999999999999995 с остатком 0,199999999999999991.

В выражении для decimalRemainderсимвол литерального типа D приводит оба операнда к Decimal, а 0,2 имеет точное представление. Mod Поэтому оператор возвращает ожидаемый остаток 0,0.

Обратите внимание, что недостаточно объявить decimalRemainder как Decimal. Также необходимо принудительно принудить литералы к Decimal, иначе они используются Double по умолчанию и получают то же неточное значение, что doubleRemainderи decimalRemainder .

Логический тип не преобразуется в числовой тип точно

Логические значения типа данных не хранятся в виде чисел, и хранимые значения не предназначены для того, чтобы быть эквивалентными числам. Для обеспечения совместимости с более ранними версиями Visual Basic предоставляет ключевые слова преобразования (функция CType, CBool, CIntи т. д.) для преобразования между Boolean и числовыми типами. Однако другие языки иногда выполняют эти преобразования по-разному, как и методы платформа .NET Framework.

Никогда не следует писать код, который использует эквивалентные числовые значения для True и False. По возможности следует ограничить использование переменных Boolean логическими значениями, для которых они предназначены. Если необходимо сочетать Boolean и числовые значения, убедитесь, что вы понимаете метод преобразования, который вы выбрали.

Преобразование в Visual Basic

При использовании CType ключевых слов преобразования или CBool для преобразования числовых типов данных в Booleanзначение 0 становится False , а все остальные значения становятся True. При преобразовании Boolean значений в числовые типы с помощью ключевых слов преобразования становится 0, False а True — -1.

Преобразование в платформе

Метод ToInt32Convert класса в пространстве имен преобразуется True в System +1.

Если необходимо преобразовать Boolean значение в числовой тип данных, будьте внимательны к используемому методу преобразования.

Символьный литерал создает ошибку компилятора

При отсутствии символов типа в Visual Basic предполагается, что для литералы используются типы данных по умолчанию. Тип по умолчанию для символьного литерала, заключенного в кавычки (" "), — .String

Тип String данных не расширяется до типа данных Char. Это означает, что если вы хотите назначить литерал переменной Char , необходимо либо выполнить сужающее преобразование, либо принудительно применить литерал к типу Char .

Создание литерала Char для назначения переменной или константе
1. Объявите переменную или константу как Char.
2. Заключите значение символа в кавычки (" ").
3. Следуйте закрывающим двойным кавычкам с символом C литерального типа, чтобы принудить литерал к Char. Это необходимо, если параметр проверки типа (оператор Option Strict) имеет значение On, и в любом случае это желательно.

В следующем примере показаны как неудачные, так и успешные назначения литерала переменной 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")

Использование сужающих преобразований всегда сопряжено с риском, так как они могут завершиться ошибкой во время выполнения. Например, преобразование из String в может завершиться Char ошибкой, String если значение содержит более одного символа. Поэтому лучше использовать C символ типа.

Преобразование строк завершается сбоем во время выполнения

Строковый тип данных участвует в очень мало расширенных преобразованиях. String расширяется только на себя и Object, и только Char и Char() ( Char массив) расширяется до String. Это связано с тем, что String переменные и константы могут содержать значения, которые не могут содержать другие типы данных.

Если параметр проверки типа (оператор Option Strict) имеет значение On, компилятор запрещает все неявные сужающие преобразования. Сюда входят те, которые включают String. Код по-прежнему может использовать ключевые слова преобразования, такие как CStr и функция CType, которые направляют платформа .NET Framework на попытку преобразования.

Примечание

Ошибка сужения-преобразования подавляется для преобразований элементов в коллекции в For Each…Next переменную управления циклом. Дополнительные сведения и примеры см. в разделе "Сужающие преобразования" статьи For Each... Следующая инструкция.

Защита от сужения преобразования

Недостаток сужения преобразований заключается в том, что они могут завершать ошибку во время выполнения. Например, если переменная String содержит что-либо, отличное от "True" или "False", ее нельзя преобразовать в Boolean. Если он содержит знаки препинания, преобразование в любой числовой тип завершается ошибкой. Если вы не знаете, что переменная String всегда содержит значения, которые может принять тип назначения, не следует пытаться выполнить преобразование.

Если необходимо преобразовать данные из String в другой тип данных, самая безопасная процедура заключается в том, чтобы заключить попытку преобразования в ... Поймать... Оператор Finally. Это позволяет справиться со сбоем во время выполнения.

Массивы символов

Один и Char массив Char элементов расширяются до String. Однако String не расширяется до Char(). Чтобы преобразовать String значение в Char массив, можно использовать ToCharArray метод System.String класса .

Бессмысленные значения

Как правило, String значения не являются значимыми в других типах данных, а преобразование является очень искусственным и опасным. По возможности следует ограничить использование переменных String последовательности символов, для которых они предназначены. Никогда не следует писать код, который использует эквивалентные значения в других типах.

См. также раздел