Strange behavior of the If () operator

Today I stumbled upon the weird behavior of the VB.net If () operator. Perhaps you can explain why it works as if it is possible, or maybe you can confirm that this is a mistake.

So, I have an SQL database with a table "TestTable" with an int column "NullableColumn", which may contain NULL. I would like to read the contents of this column.

So, I declare a type variable Nullable(Of Integer), for this I need to open the SqlClient.SqlDataReader"SELECT NullableColumn FROM TestTable" and use the following code to get the contents 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 contenthas a value of 0, and not Nothing, as I expected.

When debugging, everything looks good, so

  • reader.GetOrdinal("NullableColumn") ( 0)
  • reader.IsDBNull(0) reader.IsDBNull(reader.GetOrdinal("NullableColumn")) True, NULL
  • If(1=2, Nothing, "Not Nothing") " "
  • If(1=1, Nothing, "Not Nothing") Nothing
  • reader.GetInt32(reader.GetOrdinal("NullableColumn")) , NULL Integer

, 0?

+5
3

VB . If . , , , , If , Int32. IsDBNull true, If Nothing Int32. VB Nothing . Int32 0.

MSDN Nothing:

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.

, , :

If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then
    content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))
End If 

If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))
+5

content 0, Nothing, .

content?

, content.HasValue. False Nothing True, .

InvalidOperationException content.Value, .

+1

, , , .

, . , , , If .

Dim content = If(reader.IsDBNull(reader.GetOrdinal("NullableColumn")),
                DirectCast(Nothing, Integer?),
                reader.GetInt32(reader.GetOrdinal("NullableColumn")))

New Integer?() DirectCast.

Of course, it is now contentdeclared inside the block Using- this may not be what you want, but you should try to make the declaration as local as possible.

In addition, this code is complex and is likely to be reused. I suggest creating a separate (expansive) method for converting database NULL values ​​to nullables:

<Extension> _
Public Shared Function GetNullable(Of T)(SqlClient.SqlDataReader this, String fieldName) As T?
    Dim i = this.GetOrdinal(fieldName)
    Return If(this.IsDBNull(i), New T?(), this.GetFieldValue(Of T)(i))
End Function

Now you can use it as follows:

Dim content = reader.GetNullable(Of Integer)("NullableColumn")
+1
source

All Articles