Поделиться через


Устранение неполадок типов данных (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 не возвращает точный результат

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

Тип десятичных данных не использует представление с плавающей запятой. Многие числа, которые являются нетекстными Single и Double точными 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 цифр.

DoubleТак как zeroPointTwo значение 0,2 является бесконечно повторяющейся двоичной дроби с сохраненным значением 0,20000000000000000000001. Деление 2.0 на это количество дает 9,99999999999999995 с оставшейся частью 0,199999999999991.

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

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

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

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

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

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

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

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

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

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

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

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

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

Создание литерала Char для назначения переменной или константе
1. Объявите переменную или константу как Char.
2. Заключите значение символа в кавычки (" ").
3. Выполните закрывающий двойный кавычки символом литерального типа C , чтобы принудительно выполнить литерал Char. Это необходимо, если параметр проверки типа (option Strict Statement) имеет значение 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")

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

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

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

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

Замечание

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

Сужение защиты преобразования

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

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

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

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

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

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

См. также