How should I cast from an Object to an Integer in VB.NET?
When I do:
Dim intMyInteger as Integer = TryCast(MyObject, Integer)
it says:
TryCast operand must be reference type, but Integer is a value type.
TryCast is the equivalent of C#'s as operator. It is a "safe cast" operator that doesn't throw an exception if the cast fails. Instead, it returns Nothing (null in C#). The problem is, you can't assign Nothing (null) (a reference type) to an Integer (a value type). There is no such thing as an Integer null/Nothing.
Instead, you can use TypeOf and Is:
If TypeOf MyObject Is Integer Then
intMyInteger = DirectCast(MyObject, Integer)
Else
intMyInteger = 0
End If
This tests to see if the runtime type of MyObject is Integer. See the MSDN documentation on the TypeOf operator for more details.
You could also write it like this:
Dim myInt As Integer = If(TypeOf myObj Is Integer, DirectCast(myObj,Integer), 0)
Furthermore, if an integer with a default value (like 0) is not suitable, you could consider a Nullable(Of Integer) type.
MyObject be Integer when we already know it is Object?MyObject is an Object reference. It could still point to an object of any type. The If TypeOf x Is type expression tests the runtime type of the object.String "1" to an integer 1 is not a cast. It is a conversion (the string is parsed). The OP is specifically asking about casting an Object reference that he's assuming is an integer to an integer value. I'd appreciate those rep points back, thank you.IIf here would fail (cause an exception if myObj is not an Integer). IIf always evaluates BOTH the true and false expressions; and then it returns whichever one is appropriate. The point of If(..) is that it only evaluates one expression or the other. In this case, it does not do DirectCast unless we have verified that we have an Integer. There is no situation in which using IIf(..) is a benefit; all uses of it in modern VB should be replaced by If(..).You can use this:
Dim intMyInteger as Integer
Integer.TryParse(MyObject, intMyInteger)
Use Directcast and catch InvalidCastException
The equivalent for TryCast is CType. Both will do a type conversion if it is possible. By contrast, DirectCast will only convert the type if it is that type already.
To illustrate, you can use CType to convert a String, or Short, or Double, to an Integer. DirectCast will generally give you a syntax/compile error if you do that; but if you try to go around the error by using type Object (this is called "boxing" and "unboxing"), it will throw an exception at run-time.
Dim OnePointTwo As Object = "1.2"
Try
Dim temp = CType(OnePointTwo, Integer)
Console.WriteLine("CType converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
Catch ex As Exception
Console.WriteLine("CType threw exception")
End Try
Try
Dim temp = DirectCast(OnePointTwo, Integer)
Console.WriteLine("DirectCast converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
Catch ex As Exception
Console.WriteLine("DirectCast threw exception")
End Try
This will output:
CType converted to: 1 (type: System.Int32)
DirectCast threw exception
So to most closely follow the TryCast semantics, I suggest using a function like this:
Shared Function TryCastInteger(value As Object) As Integer?
Try
If IsNumeric(value) Then
Return CType(value, Integer)
Else
Return Nothing
End If
Catch ex As Exception
Return Nothing
End Try
End Function
And to illustrate its effect:
Shared Sub TestTryCastInteger()
Dim temp As Integer?
Dim OnePointTwo As Object = "1.2"
temp = TryCastInteger(OnePointTwo)
If temp Is Nothing Then
Console.WriteLine("Could not convert to Integer")
Else
Console.WriteLine("TryCastInteger converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
End If
Dim NotANumber As Object = "bob's your uncle"
temp = TryCastInteger(NotANumber)
If temp Is Nothing Then
Console.WriteLine("Could not convert to Integer")
Else
Console.WriteLine("TryCastInteger converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
End If
End Sub
Running TestTryCastInteger() will output:
TryCastInteger converted to: 1 (type: System.Int32)
Could not convert to Integer
There also is such a thing as a null/Nothing Integer, or any other static type, called a "nullable" type, see Variable declaration question mark for some more information. But that does not really make it a "reference" type either.
TryCast does not attempt the full range of conversions that CType attempts. The two are used quite differently. TryCast is a very strict (and fast) conversion: it attempts to "upcast" to a specific subclass. It is used when it was necessary to pass an instance as a more general base class. CType can do many more conversions -- which is good or bad ..Object declaration, and you are expecting a value type, then the safe way to proceed is to start testing the object's type. Decide what to do, once you know what type of object you have.
Cint(or any other conversion call) has a different purpose thanTryCast/DirectCast. It is sensible if you have an incoming numeric value type, e.g. Single or Double, and want to truncate it to an Integer. Applying it to an incomingObjectmeans you have no clue what is coming in, and what conversion work will be attempted. IMHO, it is a risky style of programming. Do what Jonathan shows, extending it if necessary. E.g., if you want to Parse a String, then check if its type is String, then call TryParse. Be explicit.INumeric(or whatever) interface. Given that, instead of an incomingMyObject As Objectone could have an incomingMyNumber As INumeric. OK, now we know "enough" about what is coming in, to doCInt(MyNumber), and be confident that we know what work will be done.Object. I consider that a "code smell". I am recommending not using conversion operators until you have identified some interface or base class - so that you have some clue what you are asking to be done, and what might go wrong. Know whether you are asking for string parsing, or numeric truncation, or merely "unboxing".