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

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

Выражения с плавающей запятой не сравниваются в равенстве

При работе с числами с плавающей запятой (Тип данных Single (Visual Basic) и Тип данных Double (Visual Basic)), помните, что они хранятся в виде двоичных дробей. Это означает, что они не содержат точное представление любого числа, которое не является двоичной дробью (формы 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 (Visual Basic) может возвращать непредвиденный результат, когда по крайней мере один из операндов является числом с плавающей запятой.

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

Так как zeroPointTwo относится к типу Double, значение для 0,2 является периодической бесконечной двоичной дробью, которая хранится в виде значения 0,20000000000000001. Деление числа 2,0 на это число дает 9,9999999999999995 с остатком 0,19999999999999991.

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

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

Тип Boolean не преобразовывает в числовой тип точно

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

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

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

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

Преобразование в Framework

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

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

Знак Literal порождает ошибку компилятора

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

Тип данных String не расширяется до Тип данных Char (Visual Basic). Это означает, что если вы хотите назначить литерал к переменной 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 (Visual Basic) участвует лишь в небольшом числе расширяющих преобразований. String расширяется только до себя и типа Object, и только типы Char и Char() (массив Char) расширяются до типа String. Это происходит потому, что переменные и константы String могут содержать значения, которые другие типы данных не могут содержать.

Если переключатель проверки типа (Оператор Option Strict) является On, компилятор запрещает все неявные сужающие преобразования. Это включает те включающие String. В коде можно по-прежнему использовать ключевые слова преобразования, такие как CStr и Функция CType (Visual Basic), которые направляют .NET Framework, чтобы сделать попытку преобразования.

Примечание

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

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

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

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

Массив знаков.

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

Не имеющие смысла значения

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

См. также

Ссылки

Сводка типов данных (Visual Basic)

Функции преобразования типов (Visual Basic)

Основные понятия

Типы данных в Visual Basic

Символы типов (Visual Basic)

Типы значений и ссылочные типы

Эффективное использование типов данных (Visual Basic)

Другие ресурсы

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