VB6 Can IsNumeric be wrong?

2019-04-29 16:24发布

Is it possible to test a string with IsNumeric() and for it to return true, but when you cast that same string to an integer using CInt() and assign it to a variable of type integer that it will give a type mismatch error?

I ask because I was getting a type mismatch error, so I used IsNumeric() to check the string was numeric before trying to cast it, but I still get the error.

I am tearing my hair out with this.

Here is the code in question. iGlobalMaxAlternatives = CInt(strMaxAlternatives) is where the error is occuring.

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条回答
Animai°情兽
2楼-- · 2019-04-29 17:05

You may have an overflow due the maximum integer size; the currency type actually does very well for large numbers (but beware of any regional issues). See edits below for Int64 discussion.

According to MSDN documentation on IsNumeric:

  • IsNumeric returns True if the data type of Expression is Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong, or UShort, or an Object that contains one of those numeric types. It also returns True if Expression is a Char or String that can be successfully converted to a number.

  • IsNumeric returns False if Expression is of data type Date or of data type Object and it does not contain a numeric type. IsNumeric returns False if Expression is a Char or String that cannot be converted to a number.

Since you are getting a Type Mismatch, perhaps a Double is interfering with the conversion. The IsNumeric does not guarantee it is an Integer, just that it matches one of the numeric possibilities. If the number is a double, perhaps regional settings (comma versus period and so on) are causing the exception.

You might try converting it to a double and then to an integer.

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

EDIT: After your clarification, it appears you are getting an overflow conversion. First try using a Long and CLng() instead of CInt(). There is still a chance the entry is Int64 though, which is more difficult using VB6.

I have used the following code for the LARGE_INTEGER and Integer8 types (both Int64), but it may not work for your situation:

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

This example was from an LDAP password expiration example, but like I said it may or may not work in your scenario. If you don't have the LARGE_INTEGER type, it looks like:

Private Type LARGE_INTEGER
    LowPart As Long
    HighPart As Long
End Type

Search for LARGE_INTEGER and VB6 for more information.

EDIT: For debugging, it may be useful to temporarily avoid error handling and then turn it back on after passing the troubling lines:

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楼-- · 2019-04-29 17:05

According to the VB6 documentation, "IsNumeric returns True if the data type of Expression is Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong, or UShort, or an Object that contains one of those numeric types. It also returns True if Expression is a Char or String that can be successfully converted to a number."

Many of those cannot be converted to an Integer. For example "1.5" is numeric but it's not an integer. So, you can convert it to a number, but not necessarily an integer.

查看更多
可以哭但决不认输i
4楼-- · 2019-04-29 17:08

Yes. Try this:

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

This one's an overflow, but I think it illustrates the unreliability of IsNumeric() in general (especially for ints - for doubles it's much more reliable).

查看更多
叼着烟拽天下
5楼-- · 2019-04-29 17:09

The following code works without a Type Mismatch error in Visual BASIC 6

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

The same for this variant

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

Posting the code in question would help answer your question. Basically there are several function in VB6 that are used to convert strings into number.

CInt and Int convert into number but handle rounding different. Direct assignment works and equivalent to using CInt. Howver I recommend continuing to use CInt to make the operation clear to you and your fellow developers in the future.

CInt works on number with commas like "3,041.41" However VB6 has problem handling region settings so if you are using notation other than standard American English you will get strange results and errors.

查看更多
forever°为你锁心
6楼-- · 2019-04-29 17:13

Yes, "3.41" would be numeric but not an integer.

查看更多
混吃等死
7楼-- · 2019-04-29 17:18

Just found this nugget. If you run the following, script #1 returns TRUE but script #2 & #3 will fail:

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

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

SELECT CONVERT(NUMERIC(11,4), '98,0')     -- Fails
查看更多
登录 后发表回答