If()语句的奇怪行为

时间:2013-04-18 07:58:17

标签: vb.net

今天我偶然发现了VB.net If()语句的奇怪行为。也许你可以解释为什么它像它一样工作,或者你可以确认它是一个bug。

所以,我有一个带有“TestTable”表的SQL数据库,其中一个int列“NullableColumn”可以包含NULL。我想宣读本专栏的内容。

所以我声明了一个Nullable(Of Integer)类型的变量,为“SELECT NullableColumn FROM TestTable”打开一个SqlClient.SqlDataReader并使用以下代码来获取该列的内容:

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

但在此之后,我的变量content的值为0,而不是我预期的Nothing

调试时,一切看起来都没问题,所以

  • reader.GetOrdinal("NullableColumn")提供此列的正确序号位置(为0)
  • reader.IsDBNull(0)reader.IsDBNull(reader.GetOrdinal("NullableColumn"))传递True,因为此列的内容确实为NULL
  • If(1=2, Nothing, "Not Nothing")发送字符串“Not Nothing”
  • If(1=1, Nothing, "Not Nothing")发送Nothing
  • reader.GetInt32(reader.GetOrdinal("NullableColumn"))抛出错误,因为NULL无法转换为Integer

那么,为什么我的变量的值为0?

3 个答案:

答案 0 :(得分:5)

在VB中,Nothing与null不同。 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会效果最好:

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

答案 1 :(得分:1)

  

但在此之后,我的变量content的值为0,而不是我预期的Nothing

如何查看content值?

首先,您应该从content.HasValue属性开始。当您从数据库中获取正确的值时,FalseNothing的情况应为True

在没有价值的情况下访问InvalidOperationException时,您还应该content.Value

答案 2 :(得分:1)

克里斯已经给出了解释,但我不喜欢他所选择的作业风格,因为它将作业与变量声明分开。

相比之下,我建议在声明时初始化变量。在这种情况下,由于您需要首先将If的运算符强制转换为正确的类型,因此它确实有点复杂。

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

实际上,您也可以使用稍短New Integer?()而不是DirectCast

当然现在在content块内声明了Using - 这可能不是你想要的,但你应该尝试使声明尽可能本地化。< / p>

此外,此代码很复杂,可能会重复使用。我建议创建一个单独的(扩展)方法,将数据库NULL值转换为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

现在您可以按如下方式使用它:

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