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