today I stumbled upon a strange behaviour of the VB.net If() statement. Maybe you can explain why it is working like it does, or maybe you can confirm that it is a bug.
So, I have a SQL database with a table “TestTable” with an int column “NullableColumn” that can contain NULL. I’d like to read out the content of this column.
So I declare a variable of type Nullable(Of Integer)
for that matter, open a SqlClient.SqlDataReader
for “SELECT NullableColumn FROM TestTable” and use the following code to get the content of this column:
Dim content as Nullable(Of Integer)
...
Using reader as SqlClient.SqlDataReader = ...
content = If(reader.IsDBNull(reader.GetOrdinal("NullableColumn")), Nothing, reader.GetInt32(reader.GetOrdinal("NullableColumn")))
End Using
But after that my variable content
has the value 0, not Nothing
as I would have expected.
When debugging everything looks alright, so
reader.GetOrdinal("NullableColumn")
delivers the correct ordinal position of this column (which is 0)reader.IsDBNull(0)
andreader.IsDBNull(reader.GetOrdinal("NullableColumn"))
deliverTrue
, since the content of this column indeed is NULLIf(1=2, Nothing, "Not Nothing")
delivers the String “Not Nothing”If(1=1, Nothing, "Not Nothing")
deliversNothing
reader.GetInt32(reader.GetOrdinal("NullableColumn"))
throws an error, since NULL can’t be converted toInteger
So, why does my variable has the value 0?
Solution:
In VB Nothing is not the same as null. The If operator must determine the type of its result based on the arguments passed to it. Nothing, of course, has no type so the only type that the If operator can return in your code is Int32. If the IsDBNull method returns true, then the If operator returns Nothing cast as Int32. In VB, Nothing returns the default value for a type. For an Int32, the default value is 0.
From MSDN on the Nothing keyword:
Nothing represents the default value of a data type. The default value depends
on whether the variable is of a value type or of a reference type.
For non-nullable value types, Nothing in Visual Basic differs from null in C#.
In Visual Basic, if you set a variable of a non-nullable value type to Nothing,
the variable is set to the default value for its declared type. In C#, if you
assign a variable of a non-nullable value type to null, a compile-time error
occurs.
I think just a regular If would work best:
If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then
content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))
End If
Or to keep it shorter
If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))