2013-04-18 51 views
5

hôm nay tôi tình cờ gặp một hành vi kỳ lạ của câu lệnh VB.net If(). Có lẽ bạn có thể giải thích lý do tại sao nó hoạt động như nó, hoặc có thể bạn có thể xác nhận rằng đó là một lỗi.Hành vi lạ của câu lệnh If()

Vì vậy, tôi có một cơ sở dữ liệu SQL với một bảng "TestTable" với một cột int "NullableColumn" có thể chứa NULL. Tôi muốn đọc nội dung của cột này.

Vì vậy, tôi khai báo một biến kiểu Nullable(Of Integer) cho rằng vấn đề, mở một SqlClient.SqlDataReader cho "SELECT NullableColumn TỪ testtable" và sử dụng đoạn mã sau để có được nội dung của cột này:

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 

Nhưng sau đó tôi biến content có giá trị 0, không phải là Nothing như tôi mong đợi.

Khi gỡ lỗi tất cả mọi thứ trông ổn, vì vậy

  • reader.GetOrdinal("NullableColumn") mang lại đúng vị trí thứ tự của cột này (đó là 0)
  • reader.IsDBNull(0)reader.IsDBNull(reader.GetOrdinal("NullableColumn")) cung cấp True, vì nội dung của cột này thực sự là NULL
  • If(1=2, Nothing, "Not Nothing") phân phối chuỗi "Không có gì"
  • If(1=1, Nothing, "Not Nothing") cung cấp Nothing
  • reader.GetInt32(reader.GetOrdinal("NullableColumn")) ném một lỗi, vì NULL không thể được chuyển đổi sang Integer

Vì vậy, tại sao không biến tôi có giá trị 0?

+0

Bạn đã sử dụng một Nếu bình thường - sau đó - tuyên bố elese? Nó có hoạt động không? –

+0

Không quan tâm bạn đã bật 'Tùy chọn Strict' chưa? Nếu không, bạn nên –

+0

Có, tôi đã thử một bình thường 'Nếu ... Sau đó ... Khác ...' statemant, và điều này làm việc. Bật 'Tùy chọn Strict' không thay đổi gì cả. – Nostromo

Trả lời

5

Trong VB Không có gì không giống như null. Toán tử If phải xác định loại kết quả của nó dựa trên các đối số được truyền cho nó. Không có gì, tất nhiên, không có kiểu để loại duy nhất mà toán tử If có thể trả về trong mã của bạn là Int32. Nếu phương thức IsDBNull trả về true, thì toán tử If trả về Không có gì cast thành Int32. Trong VB, Không có gì trả về giá trị mặc định cho một loại. Đối với Int32, giá trị mặc định bằng 0.

Từ MSDN trên từ khóa Không có gì:

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. 

Tôi nghĩ chỉ là một Nếu thường xuyên sẽ làm việc tốt nhất:

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

Hoặc để giữ cho nó ngắn hơn

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

Nhưng sau đó biến của tôi content có giá trị 0, không phải Nothing như tôi đã mong đợi.

Làm cách nào để kiểm tra giá trị content?

Trước hết, bạn nên bắt đầu với thuộc tính content.HasValue. Nó phải là False cho trường hợp của bạn là NothingTrue khi giá trị chính xác được tìm nạp từ cơ sở dữ liệu.

Bạn cũng sẽ nhận được InvalidOperationException khi truy cập content.Value khi không có giá trị.

+0

Nếu tôi di chuyển chuột qua một biến trong chế độ gỡ lỗi, tôi thấy nội dung của biến này. Một kiểu đối tượng nullable hiển thị 'Nothing', nếu nó không có giá trị và giá trị thực tế, nếu nó có. Nếu tôi sử dụng câu lệnh 'If ... Then ... Khác ...', Intellisense hiển thị 'Nothing', nếu tôi sử dụng' If (...) 'statemant, Intellisense hiển thị 0. – Nostromo

1

Chris đã đưa lời giải thích nhưng tôi không thích phong cách của bài tập mà anh ấy đã chọn vì nó chia tách bài tập từ biến declarati trên.

Ngược lại, tôi khuyên bạn nên khởi tạo biến khi khai báo. Trong trường hợp này, nó được cho là hơi phức tạp vì bạn cần phải nhập toán tử If vào đúng loại đầu tiên.

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

Thực ra bạn cũng có thể sử dụng New Integer?() hơi ngắn hơn thay vì DirectCast. Tất nhiên bây giờ content được khai báo bên trong khối Using - đây có thể không phải là những gì bạn muốn nhưng bạn nên thử để làm cho tuyên bố là địa phương nhất có thể.

Hơn nữa, mã này rất phức tạp và có thể sẽ được sử dụng lại. Tôi khuyên bạn nên tạo một phương pháp riêng biệt (phần mở rộng) để chuyển đổi các giá trị NULL cơ sở dữ liệu để 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 

Bây giờ bạn có thể sử dụng nó như sau:

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