VB6 Может ли номер ошибаться? - PullRequest
5 голосов
/ 22 января 2009

Можно ли проверить строку с помощью 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 ]

6 голосов
/ 22 января 2009

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

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

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

  • IsNumeric возвращает False, если выражение имеет тип данных Дата или типа данных Объект, и он не содержит числовой тип. 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 голосов
/ 22 января 2009

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

2 голосов
/ 22 января 2009

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

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

1 голос
/ 22 января 2009

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

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

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

1 голос
/ 22 января 2009

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

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

0 голосов
/ 29 января 2010

Только что нашел этот самородок. Если вы выполните следующее, скрипт № 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
0 голосов
/ 22 января 2009

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

Изменение

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
0 голосов
/ 22 января 2009

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

0 голосов
/ 22 января 2009

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

0 голосов
/ 22 января 2009

Следующий код работает без ошибки несоответствия типов в 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 имеет проблемы с настройкой региона, поэтому, если вы используете нотацию, отличную от стандартного американского английского, вы получите странные результаты и ошибки.

...