2013-04-18 118 views
5

今天我偶然發現了VB.net If()語句的奇怪行爲。也許你可以解釋爲什麼它像它那樣工作,或者你可以確認它是一個錯誤。If()語句的奇怪行爲

所以,我有一個帶有「TestTable」表的SQL數據庫,其中包含一個可以包含NULL的int列「NullableColumn」。我想宣讀本專欄的內容。

所以我宣佈Nullable(Of Integer)類型的變量對於這個問題,打開SqlClient.SqlDataReader爲「選擇NullableColumn從TestTable的」,並使用下面的代碼來獲得本專欄的內容:

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,因爲此列確的內容爲空時
  • If(1=2, Nothing, "Not Nothing")交付字符串「不是Nothing」
  • If(1=1, Nothing, "Not Nothing")交付Nothing
  • reader.GetInt32(reader.GetOrdinal("NullableColumn"))拋出一個錯誤,因爲NULL不能轉換爲Integer

那麼,爲什麼我的變量的值是0?

+0

你已經使用了正常的如果 - 那麼 - elese聲明:

<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 

現在,您可以按如下方式使用它?它工作嗎? –

+0

出於興趣,你是否打開了Option Strict?如果不是,你應該 –

+0

是的,我嘗試了一個正常的'如果...那麼...否則...'語句,這工作。打開Option Strict並沒有改變任何事情。 – Nostromo

回答

5

在VB中沒有什麼不同於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 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

但在那之後我的變量content具有價值0,不Nothing因爲我本來期望。

如何檢查content值?

首先,您應該從content.HasValue屬性開始。當你從數據庫中提取正確的值時,你的NothingTrue的情況應該是False

您還應該得到InvalidOperationException,當它沒有得到價值時訪問content.Value

+0

如果我將鼠標放在調試模式下的變量上,我會看到這個變量的內容。一個可爲空的對象類型顯示「Nothing」,如果沒有值和實際值,則顯示爲「Nothing」。 如果我使用正常的「If ... Then ... Else ...'語句,則Intellisense將顯示」Nothing「,如果我使用If(...)語句,Intellisense將顯示0。 – Nostromo

1

克里斯給解釋,但我不喜歡他選擇的作業風格,因爲它從變量聲明中分配賦值上。

相比之下,我建議在申報時初始化變量。在這種情況下,由於您需要首先將If的任一運算符投射到正確的類型,所以無疑會稍微複雜。

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

其實你也可以使用略短New Integer?()代替DirectCast的。

當然現在content聲明的Using塊內 - 這可能不是你想要什麼,但你應儘量作出該聲明的地方越好。

此外,這段代碼很複雜,可能會被重複使用。我建議創建一個單獨的(擴展)方法的數據庫NULL值轉換爲nullables:

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