VB6 Может ли номер ошибаться?

Можно ли протестировать строку с помощью IsNumeric() и вернуть ей значение true, но когда вы приведете эту же строку к целому числу с помощью CInt() и назначите ее переменной типа integer, она выдаст ошибку несоответствия типов?

Я спрашиваю, потому что я получаю ошибку несоответствия типов, поэтому я использовал IsNumeric(), чтобы проверить, что строка числовая, прежде чем пытаться ее привести, но я все еще получаю ошибку.

Я рву на себе волосы этим.

Вот код, о котором идет речь.iGlobalMaxAlternatives = CInt(strMaxAlternatives) где ошибка происходит.

Dim strMaxAlternatives As String
Dim iGlobalMaxAlternatives As Integer
iGlobalMaxAlternatives = 0
bSurchargeIncInFare = True

strMaxAlternatives = ReadStringKeyFromRegistry("Software\TL\Connection Strings\" & sConn & "\HH", "MaxAlt")

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
End If

10 ответов

Решение

У вас может быть переполнение из-за максимального целочисленного размера; тип валюты на самом деле очень хорошо подходит для больших чисел (но остерегайтесь любых региональных проблем). См. Правки ниже для обсуждения Int64.

Согласно документации MSDN на IsNumeric:

  • IsNumeric возвращает True, если тип данных Expression - логический, байтовый, десятичный, двойной, целочисленный, длинный, SByte, короткий, одинарный, UInteger, ULong или UShort, или объект, содержащий один из этих числовых типов. Он также возвращает True, если Expression является Char или String, которые могут быть успешно преобразованы в число.

  • IsNumeric возвращает значение False, если выражение имеет тип данных Date или тип данных Object и не содержит числового типа. IsNumeric возвращает False, если Expression - это Char или String, которые нельзя преобразовать в число.

Так как вы получаете несоответствие типов, возможно, двойник мешает преобразованию. IsNumeric не гарантирует, что это целое число, только то, что оно соответствует одной из числовых возможностей. Если число двойное, возможно, региональные настройки (запятая или точка и т. Д.) Вызывают исключение.

Вы можете попытаться преобразовать его в двойное, а затем в целое число.

' Using a couple of steps
Dim iValue As Integer
Dim dValue As Double
dValue = CDbl(SourceValue)
iValue = CInt(iValue)
' Or in one step (might make debugging harder)
iValue = CInt(CDbl(SourceValue))

РЕДАКТИРОВАТЬ: после вашего разъяснения, кажется, вы получаете переполнение преобразования. Сначала попробуйте использовать Long и CLng() вместо CInt(). Тем не менее, существует вероятность, что запись будет Int64, что сложнее при использовании VB6.

Я использовал следующий код для типов LARGE_INTEGER и Integer8 (оба типа Int64), но он может не работать в вашей ситуации:

testValue = CCur((inputValue.HighPart * 2 ^ 32) + _
                  inputValue.LowPart) / CCur(-864000000000)

Этот пример взят из примера истечения срока действия пароля LDAP, но, как я уже сказал, он может или не может работать в вашем сценарии. Если у вас нет типа LARGE_INTEGER, он выглядит следующим образом:

Private Type LARGE_INTEGER
    LowPart As Long
    HighPart As Long
End Type

Найдите LARGE_INTEGER и VB6 для получения дополнительной информации.

РЕДАКТИРОВАТЬ: Для отладки может быть полезно временно избежать обработки ошибок и затем включить его снова после прохождения тревожных строк:

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    On Error Resume Next
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
    If Err.Number <> 0 Then
        Debug.Print "Conversion Error: " & strMaxAlternatives & _
                    " - " & Err.Description
    EndIf
    On Error Goto YourPreviousErrorHandler
End If

Да, "3.41" будет числовым, но не целым числом.

VB6 не предоставляет хороших методов, чтобы гарантировать, что CInt не потерпит неудачу. Я нашел самый простой способ - просто использовать обработку ошибок.

function TryParse(byval text as string, byref value as integer) as boolean
  on error resume next
  value = CInt(text)
  TryParse = (err.number = 0)
endfunction

Конечно, ваши настройки обработки ошибок могут отличаться.

Согласно документации VB6, "IsNumeric возвращает True, если тип данных Expression - логический, байтный, десятичный, двойной, целочисленный, длинный, SByte, короткий, одиночный, UInteger, ULong или UShort, или объект, содержащий один из них. числовые типы. Он также возвращает True, если Expression является Char или String, которые могут быть успешно преобразованы в число."

Многие из них не могут быть преобразованы в целое число. Например, "1.5" - это число, но не целое число. Таким образом, вы можете преобразовать его в число, но не обязательно целое число.

Да. Попробуй это:

If IsNumeric("65537") Then
    Dim i As Integer
    i = CInt("65537") 'throws an error on this line!
End If

Это переполнение, но я думаю, что оно иллюстрирует ненадежность IsNumeric() в целом (особенно для целых чисел - для двойников это намного надежнее).

Лучше всего начать регистрировать ошибки с фактическими значениями, с которыми они работают, чтобы вы могли понять, что происходит.

Просто нашел этот самородок. Если вы выполните следующее, скрипт № 1 вернет TRUE, но скрипт № 2 и № 3 завершится ошибкой:

SELECT ISNUMERIC('98,0') AS isNum   -- Fails

SELECT CONVERT(INT, '98,0')   -- Fails

SELECT CONVERT(NUMERIC(11,4), '98,0')     -- Fails

Следующий код работает без ошибки несоответствия типов в Visual BASIC 6

Dim I As Integer
I = CInt("3.41")

То же самое для этого варианта

Dim I As Integer
Dim TempS As String
TempS = "3.41"
I = CInt(TempS)

Размещение соответствующего кода поможет ответить на ваш вопрос. По сути, в VB6 есть несколько функций, которые используются для преобразования строк в число.

CInt и Int конвертируются в числа, но обрабатывают округление по-разному. Прямое назначение работает и эквивалентно использованию CInt. Однако я рекомендую продолжать использовать CInt, чтобы сделать эту операцию понятной вам и вашим коллегам-разработчикам в будущем.

CInt работает с числом с запятыми, такими как "3,041.41". Однако VB6 имеет проблемы с обработкой настроек региона, поэтому, если вы используете нотацию, отличную от стандартного американского английского, вы получите странные результаты и ошибки.

IsNumeric вернет true, если сможет преобразовать строку в число. Даже если в строке есть нечисловые символы. Я всегда зацикливаю строку по одному символу за раз и проверяю каждый символ. Если один символ не работает, я могу вернуть ошибку.

Два варианта...

+ Изменить

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
End If

к

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CDbl(strMaxAlternatives) ' Cast to double instead'
End If

Или же

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    If CDbl(strMaxAlternatives) Mod 1 = 0 Then ' Make sure there\'s no decimal points'
        iGlobalMaxAlternatives = CInt(strMaxAlternatives)
    End If
End If
Другие вопросы по тегам