2010-07-19 21 views
10

Tôi vừa mới bắt đầu viết trên một thành phần mà tôi thấy có thể hữu ích khi khai báo một số thuộc tính không có giá trị, thay vì cho phép chúng đặt giá trị mặc định. Tuy nhiên, tôi nhận ra rằng trước đây tôi chưa bao giờ sử dụng cú pháp non-nullable-type? hoặc loại Nullable<T> trước đây, vì vậy có thể một số gotchas sẽ sớm nhảy ra và cắn tôi. Vì vậy, ...Gotchas khi sử dụng Nullable <T> trong C# 4

  • gotchas lớn nhất là gì khi sử dụng Nullable<T>? cú pháp viết tắt?

  • Tôi làm cách nào để khắc phục sự cố?

  • Ưu điểm lớn nhất/khả năng mới có sẵn cho tôi khi tôi bắt đầu sử dụng chúng là gì?

+9

Viết mã của bạn. Quay lại khi nó nổ tung. Nó không phải là khoa học tên lửa. –

+3

@Hans, tôi không đồng ý: đó không phải là điều xấu để cố gắng lường trước vấn đề ... Tôi chắc rằng câu trả lời sẽ hữu ích cho nhiều người –

+0

@Closers: Tôi nhận ra rằng tôi sẽ phải quay lại cộng đồng khi tôi có một vấn đề "thực sự", nhưng vì đây là một khái niệm hoàn toàn mới, tôi đã không nghĩ rằng nó sẽ làm tôi đau đớn để được giúp đỡ tìm kiếm địa hình. Nếu khái niệm này không phải là rất khó, thì có lẽ tôi đang quá thận trọng - nhưng nó có thể là một trong những lĩnh vực mà bạn đang bị ràng buộc để làm cho những sai lầm tân binh, và nơi họ có thể rất khó để phát hiện. Câu trả lời của Mark Byers là một ví dụ tuyệt vời về những điều tôi đang tìm kiếm. –

Trả lời

18

Một hình ảnh phổ biến là cố gắng gán cho một biến nullable với một biểu thức có điều kiện như sau:

bool useDefault = true; 
int defaultValue = 50; 
int? y = useDefault ? defaultValue : null; 

Thoạt nhìn này có thể trông giống như nó nên làm việc nhưng thực sự nó mang lại cho một lỗi biên dịch:

 
Type of conditional expression cannot be determined because there is no 
implicit conversion between 'int' and '<null>' 

Giải pháp: thêm một dàn diễn viên cho một hoặc cả hai khả năng xảy ra:

int? y = useDefault ? defaultValue : (int?)null; 

Ít thường thấy: thông thường nó là an toàn để giả định rằng đối với số nguyên a <= 5 và 01.tương đương. Giả thiết này không đúng với các số nguyên nullable.

int? x = null; 
Console.WriteLine(x <= 5); 
Console.WriteLine(!(x > 5)); 

Kết quả:

 
False 
True 

Giải pháp: Xử lý các trường hợp rỗng riêng biệt.


Dưới đây là một biến thể nhẹ những điều trên:

int? y = null; 
int? z = null; 
Console.WriteLine(y == z); 
Console.WriteLine(y <= z); 

Output:

 
True 
False 

Vì vậy ybằng để z, nhưng nó không phải nhỏ hơn hoặc bằng để z.

Giải pháp: Một lần nữa, xử lý trường hợp rỗng một cách riêng biệt có thể tránh được những điều bất ngờ.

+0

Entity Framework đã dạy tôi rất nhiều về các loại nullable – msarchet

1

bạn có thể làm .HasValue để kiểm tra xem biến là null

bạn có thể làm

myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar is null 

và nhiều hơn nữa, nó không phải là mới để C# 4

read this for more information

+0

Không thực sự là một "gotcha" nhưng VERY hữu ích để biết –

0

Tôi hiện không sử dụng 4.0, nhưng trong 2.0 tôi có vấn đề, giống như hầu hết Generics, int? không thể dễ dàng loại bỏ. Có lẽ 4,0 là thông minh hơn với Reflection, nhưng các tiện ích serializer XML mặc định không thể đọc nó được tiếp xúc. Nó khá là khó chịu.

+0

Tôi không biết nếu nó là khác nhau trong 2.0, nhưng trong 4,0 serializing loại chung để XML không phải là một vấn đề gì cả. .. serializing một 'Foo ' kết quả trong một phần tử '' trong XML –

+0

Trong 2.0, tôi nhận được một lỗi phản chiếu từ trình deserializer XML (tôi chỉ sử dụng mặc định) bằng cách sử dụng bất kỳ thuộc tính chung hoặc trường nào. Tôi phải string [] hoặc ArrayList vì List sẽ không serialize/deserialize. Nếu điều này là cố định trong 4.0, trái tim tôi sẽ hát với niềm vui. Làm việc trên mã kế thừa hút. –

0

Đặt giá trị mặc định một cách vô thức trong khi sử dụng giá trị rỗng. Tôi đã thấy điều này một vài lần. Ví dụ.

int? localVar = 0; 
// do something .. 
if (localVar.HasValue) 
    _myMemberValue = localVar.Value; 

Các localVar không bao giờ là null vì nó là khởi tạo với giá trị nên kiểm tra cho HasValue là alwasy đúng và _myMemberValue thể sai được gán với giá trị không đúng.

- Editied, để bổ sung thêm ý kiến ​​----

Quên đề cập đến. Một ưu điểm chính mà tôi đã thấy là sử dụng trường để biểu diễn trường Nullable trong cơ sở dữ liệu. Điều này cũng được tạo tự động nếu bạn sử dụng LINQ và EF. Nhưng theo truyền thống trước khi Nullable, nó là công việc thủ công và lỗi dễ bị xử lý cập nhật của trường và quyết định khi nào thiết lập nó với một giá trị hoặc null.

1

Nullable<T> là loại giá trị đặc biệt. Nó có thể giúp đỡ nếu bạn hiểu nó hoạt động như thế nào. Có một vài điều tinh tế về nó không rõ ràng ngay lập tức. Tôi viết blog về số here.

Khung hình thực tế - không nhiều. Chỉ cần một trong những lớn nhất là cast rõ ràng có thể ném một InvalidOperationException (và không NullReferenceException). Trình biên dịch sẽ hướng dẫn bạn về bất kỳ vấn đề nào có thể phát sinh.

1

Nullable<T> loại hơi khác thường; họ là (nghiêm túc nói) không phải giá trị cũng như các loại tài liệu tham khảo, nhưng một cái gì đó kỳ lạ ở giữa. Quyền anh/unboxing và typeof nói riêng có các quy tắc đặc biệt nên kết quả ít bất ngờ hơn.

Để biết chi tiết, tôi đề nghị sách của Jon Skeet C# in Depth. Nếu bạn không sở hữu nó, bạn nên. :)

10

Một điều gì đó mà mọi người thường ngạc nhiên là không có loại nào như một loại giá trị có thể đóng được là được đóng hộp. Nếu bạn nói:

int? x = 123; 
int? y = null; 
int z = 456; 
object xx = x; 
object yy = y; 
object zz = z; 

bạn có thể nghĩ rằng vì zz chứa int được đóng hộp, xx và yy chứa int có thể vô hiệu được đóng hộp. Họ không. xx chứa int được đóng hộp. yy được đặt thành null.

1

Một trong những cách sử dụng tốt nhất là nó ánh xạ khá tốt đến các trường cơ sở dữ liệu vô giá - lưu ý rằng, bạn muốn sử dụng nó như một trường rỗng trong cơ sở dữ liệu.

Tức là, giá trị rỗng không phải là "khác" - có nghĩa là không xác định hoặc không thể tính toán tại thời điểm này hoặc giá trị khác trong đối tượng/bản ghi này, điều này không có ý nghĩa. .tình hình của bạn có vẻ như nó là hợp lệ - sở thích người dùng có thể được null, và giá trị thực tế sẽ

actualValue = userValue ?? defaultValue; 

Các ?? là các nhà điều hành rỗng liên hiệp - ở trên là tương đương như sau:

actualValue = userValue.HasValue ? userValue : defaultValue; 

hoặc

actualValue = (userValue != null) ? userValue : defaultValue; 

Sự cám dỗ tôi thấy mọi người đưa ra vào thường xuyên nhất được sử dụng bool? như một lá cờ tri-state. Điều này không có ý nghĩa, bởi vì không có khả năng thứ ba trong true/false/???. Những người khác đọc mã của bạn sẽ phải đào sâu qua các bình luận (kịch bản trường hợp tốt nhất) để tìm ra điều đó có nghĩa là sử dụng văn bản màu xanh, sai nghĩa là văn bản màu đỏ và chữ rỗng có nghĩa là văn bản màu xanh lục. Sử dụng enums cho việc này.

Đó là cái bẫy lớn nhất tôi thấy mọi người rơi vào - khác hơn thế, chỉ được sử dụng để kiểm tra nếu nullables của bạn là null - hoặc thông qua so sánh null hoặc bằng cách sử dụng .HasValue

+0

+1 cho ghi chú về 'bool? 'Là cờ ba trạng thái =) –

Các vấn đề liên quan