Am using VS2010 VB.net
Dim Register As UInt64
Register = 12297264199100303880
If (Register And &H3FFF) = &H555 Then ' Get Overflow exception here
MsgBox("Done")
End If
Why is this happening and is there a work-around?
Your literal values are implicitly typed as long (Int64), since you didn't specify a type for them. I actually got the overflow on the assignment to Register, since the value given is too big for a long. To get this to work, just specify the type for your literal values, e.g. UL for unsigned long:
Dim Register As UInt64
Register = 12297264199100303880UL
If (Register And &H3FFFUL) = &H555UL Then
MsgBox("Done")
End If
Turning Option Strict On would be helpful, in this case. If you did, you would immediately see the problem. The problem is that the literals are interpreted as Integer (Int32) rather than ULong (UInt64). In order to force the literal to be interpreted as a ULong values, you need to add the UL type suffix:
Dim Register As UInt64
Register = 12297264199100303880UL
If (Register And &H3FFFUL) = &H555 Then ' Get Overflow exception here
MsgBox("Done")
End If
I fixed this by:
Dim DoneMask As UInt64 = &H3FFF
Dim Register As UInt64
Register = 12297264199100303880
If (Register And DoneMask) = &H555 Then ' Get Overflow exception here
MsgBox("Done")
End If
Apparently VB does better with explicit data types instead of a literal
Related
Hey all I am trying to convert a little bit of VB6 to .NET and I am getting the error of:
An unhandled exception of type 'System.InvalidCastException' occurred in Microsoft.VisualBasic.dll
Additional information: Conversion from string " " to type 'Integer' is not valid.
The following .net code is where its getting stuck at CopyMemory(str_Renamed, ptr, count):
Public Function ptrToStr(ByVal ptr As Integer) As String
Dim count As Integer
Dim str_Renamed As String
count = lstrlen(ptr)
If count Then
str_Renamed = New String(vbNullChar, count)
CopyMemory(str_Renamed, ptr, count)
ptrToStr = str_Renamed
Else
ptrToStr = ""
End If
End Function
The values for those varibles are:
count = 4
ptr = 268978536
str_Renamed = " "
I'm not sure how to go about fixing this error...
The problem looks to be that you are passing a string as the first parameter of the CopyMemory function. The CopyMemory function expects a pointer as the first parameter so the code is attempting to convert the string parameter to an integer. As far as I am aware, the only valid values for pointers are either integer values or hex values.
I do not understand at all how to use TryCast in my code, but it is something I need to use for validating user input. I have done various searches and looked at various questions on here, but no one seems to actually say how to use it, and the MSDN website doesn't seem to help at all.
Function ValidateInput(Var_In As String) As Integer
If TryCast(Var_In, Integer) = Nothing Then
Return vbNull
Else
Return Var_In
End If
End Function
The error says that
The operand must be of reference type but Integer is of value type
What is the explanation of what I have done wrong?
TryParse doesn't accept more than 10 digits so for example, an input of "12345678901" won't be accepted. How do I fix this?
Let's try to understand the differences between TryCast, Convert and TryParse.
TryCast
This function will attempt to convert one object into another type, as long as it is a reference type.
Dim MyNewObject = TryCast(MyObject, MyReferenceClass)
If IsNothing(MyNewObject) Then
MessageBox.Show("Impossible to cast")
End If
Since Integer is a value type, it will not work, so we have to figure something out...
Convert
Convert Class on MSDN
From MSDN:
Converts a base data type to another base data type.
So we can try:
Dim myInt = Convert.ToInt32(MyObject)
The problem is that it will generate an exception InvalidCastException if it's impossible to do the conversion.
TryParse
This function is trying to convert a String into something you want. And it will not generate an exception:
Dim myInt As Integer = 0
If Not Integer.TryParse(MyString, myInt) Then
MessageBox.show("This is not an integer")
End If
Limitation
Converting a String into a Integer can sometimes be tricky... If the String represents a number that is greater or lesser than Integer.MaxValue and Integer.MinValue, you will end up with no conversion...
So you can go with a Double:
Double.TryParse(MyString, MyDouble)
Or personally, if you know that it will be a number, use Decimal:
Decimal.TryParse(MyString, MyDecimal)
See Decimals on MSDN
Decimal still has a Max and Min value, according to MSDN:
The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335. The Decimal value type is appropriate for financial calculations that require large numbers of significant integral and fractional digits and no round-off errors.
Convert.ChangeType
This one is also interesting, but is a bit weird...
You are attempting to perform TryCast against an Integer, which is a value type. TryCast works only on reference types, such as (but not limited to) a Class, Object, or String type.
If you are trying to convert the input parameter to an Integer, you might try one of the methods in the Convert class, such as Convert.ToInt32() or Integer.TryParse.
Instead of TryCast, use TryParse:
Function ValidateInput(Var_In As String) As Integer
Dim iNum As Integer
If (Integer.TryParse(Var_In, iNum)) Then
Return iNum
Else
Return vbNull
End If
End Function
Much better is to use TryParse:
Function ValidateInput(Var_In As String) As Integer
Dim num as Integer
If Not Integer.TryParse(Var_In, num) Then
Return vbNull
Else
Return num
End If
End Function
I'm late to the discussion, but if anyone lands here (like I did) looking for a quick & dirty solution, here a function I'm using for simple cell validation in a DataGridView control.
Function TryTypeFit(theString As String, theType As Type, ShowError As Boolean) As Boolean
Dim TempReturn As Boolean = False
Dim TempObject As Object
Try
TempObject = Convert.ChangeType(theString, theType)
TempReturn = True
Catch ex As Exception
' didn't work
TempReturn = False
If ShowError Then
Dim eMessage As String = "Error: Value must be castable to a " & CStr(theType.Name)
MsgBox(eMessage)
End If
End Try
100:
Return TempReturn
End Function
Here is the code I have so far:
Module Module1
Sub Main()
Dim A, B, C, D As Integer
Do
Try
System.Console.WriteLine("How high is the cube?")
A = Int32.Parse(Console.ReadLine())
Catch leg As System.FormatException
System.Console.WriteLine(leg.Message)
Finally
End Try
Loop Until A =
System.Console.WriteLine("How wide is the cube?")
B = Int32.Parse(Console.ReadLine())
System.Console.WriteLine("How long is the cube?")
C = Int32.Parse(Console.ReadLine())
D = A * B * C
Console.WriteLine(D)
System.Console.ReadKey()
End Sub
End Module
I want the first try block to loop till A is an Integer in case the user inputs a letter instead of a number. Does anyone know how I might do that?
Use TryParse instead of your try/catch block in conjunction with a do loop. It returns True when it succeeds and puts the int32 value into the variable a.
Dim a As Integer, tmp As String
Do
System.Console.WriteLine("How high is the cube?")
tmp = Console.ReadLine()
Loop While Int32.TryParse(tmp, a) = False
After the loop, the value stored in a will be an integer. Repeat this for each of the other values.
You can also do like Dai does in his C# sample, and not bother storing into a temporary variable:
Dim a As Integer
Do
System.Console.WriteLine("How high is the cube?")
Loop While Int32.TryParse(Console.ReadLine(), a) = False
If you MUST do it with Try/Catch for an assignment, you can try this though for practical purposes I would do it as above.
Dim a As Integer, valid As Boolean = True
Do
Try
System.Console.WriteLine("How high is the cube?")
a = Int32.Parse(Console.ReadLine())
Catch ex As Exception
valid = False
End Try
Loop While Not valid
In C# (conversion to VB is an exercise for the reader):
public static Int32 GetInt32() {
Int32 value;
while( !Int32.TryParse( Console.ReadLine(), out value ) ) {
Console.WriteLine("Please enter an integer");
}
Console.WriteLine("You entered {0}", value);
return value;
}
Here's a real world example to further expand on one reason why using Try/Catch to control program flow is bad. At least in .NET, throwing an error and handling it in a catch takes a lot more execution time than properly handling the error using proper control flow structures.
I picked up a project from a coworker who was using a function to clean input coming in that was supposed to be numeric. He was using something like the following code to do it.
Public Shared Function SafeDouble(value As Object, Optional DefaultValue As Double = 0.0) As Double
Dim CleanDouble As Double
Try
CleanDouble = CDbl(value) 'try to convert to a double
Catch ex As Exception
CleanDouble = DefaultValue 'if it fails use the default value
End Try
Return CleanDouble
End Function
Which worked fine for the one place he was using it originally to process one row of data. The problem came about when I started using this to process 1000s of rows of data. The execution bogged down big time when it hit this section of the import.
Using some timers, I determined that it was taking between 50 and 100 milliseconds for each value that it couldn't convert and threw an exception for.
I changed the code to use a proper control structure and the time dropped to 2 to 5 milliseconds per value it couldn't convert. The current code is below. I know that it's possible that some value might come in that isn't numeric. If it isn't numeric, I just assign the default value right away.
Public Shared Function SafeDouble(value As Object, Optional DefaultValue As Double = 0.0) As Double
Dim CleanDouble As Double
Try
If IsNumeric(value) Then 'test to see if the data is numeric before converting it
CleanDouble = CDbl(value)
Else
CleanDouble = DefaultValue 'if it isn't numeric, use default value
End If
Catch ex As Exception
CleanDouble = DefaultValue 'if something unexpected happens, use default value
End Try
Return CleanDouble
End Function
As you can see, I have handled the expected error of it not converting because it isn't numeric. This should account for the majority of issues that are likely to occur. I still leave the try/catch in there in case some other, unexpected error occurs.
I have one more concept to add. Methods fire exceptions, to let you handle inlikely problems and prevent application crash. Readlin and writeline can throw exceptions, and if you dont catch them and they happen, your program will crash. Use the try block to do what its meant for: handle unlikely crashes to increae robustness. To do a thorough job you should research the exceptions and write code to prevent the crash.
I am having issues using VB.Net trying to convert a Long to a ULong.
I have tried many combinations and keep getting overflow errors.
I have a signed value of -2147483648, I know it will have a Ulong of 2151196588 once converted.
However I want to do this in a programmatic fashion because I am parsing values that can be negative and positive, but when the numbers are negative, they need to have the proper ulong value.
Note: Absolute values wont work, it needs to be a ulong for a true value.
Thank you.
If you mean reinterpret_cast<ulong>(long), then use the same technique:
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)> _
Public Structure LongULongUnion
<Runtime.InteropServices.FieldOffset(0)> Public l As Long
<Runtime.InteropServices.FieldOffset(0)> Public ul As ULong
End Structure
Sub Main()
Dim u As LongULongUnion
u.l = -2147483648L
Console.WriteLine(u.ul)
Console.ReadLine()
End Sub
But that gives 18446744071562067968 when converted.
You can use the BitConverter class:
Dim a As Int64 = -2147483648
Dim b = BitConverter.ToUInt64(BitConverter.GetBytes(a), 0)
Console.WriteLine(b.ToString) ' outputs: 18446744071562067968
Are you sure your intended value of 2151196588 is correct?
This is the easiest way to convert any Long to ULong:
Dim x As Long = -2147483648
Dim y As ULong = Not (CType((Not x), ULong)) ' = 18446744071562067968
I'm a C# programmer, so please correct me if I converted it to VB.NET incorrectly. My C# code was:
long x = -2147483648;
ulong y = ~((ulong)~x); // = 18446744071562067968
Basically you take the complement of the negative value, which is always a positive value. You can then safely cast it to ULong. Take the complement again and you have the same bit pattern cast to ULong.
Make sure you are converting your value to positive BEFORE you convert it to ulong, negatives are not in a ulong's value scope.
long: -9223372036854775808 to 9223372036854775807
ulong: 0 to 18446744073709551615
I'm using a library call, setInstance(ByVal instance As UInteger), in my VB.NET code. The parameter I need to pass is an Integer. Is there anything I need to do to convert the integer parameter to an unsigned integer? The number is guaranteed to be positive and less than 10.
Like so...
Dim MyInt As Int32 = 10
Dim MyUInt As UInt32 = CUInt(MyInt)
setInstance(MyUInt)
CUInt or CType(x, UInt) allow converting a positive integer.
It throws an exception when x is negative.
To use Int as Uint, you can use some tricks:
dim bb() = System.BitConverter.GetBytes(myInt)
dim MyUint = System.BitConverter.ToUInt32(bb, 0)
Also with System.Buffer.BlockCopy for arrays.
If you configure the compiler to disable Check Integer Overflow (default for C#). Then you can use CUInt with negative values with no check - not exception.
You can call CUint to convert a variable to a UInteger.