Vấn đề loại Nullable với ?: Toán tử có điều kiện


154

Ai đó có thể giải thích lý do tại sao điều này hoạt động trong C # .NET 2.0:

    Nullable<DateTime> foo;
    if (true)
        foo = null;
    else
        foo = new DateTime(0);

... nhưng điều này không:

    Nullable<DateTime> foo;
    foo = true ? null : new DateTime(0);

Biểu mẫu sau cho tôi một lỗi biên dịch "Loại biểu thức điều kiện có thể được xác định do không có chuyển đổi ngầm giữa '<null>' và 'System.DateTime'."

Không phải là tôi không thể sử dụng cái trước, nhưng kiểu thứ hai phù hợp hơn với phần còn lại của mã của tôi.


12
Bạn có thể tiết kiệm cho mình rất nhiều cách gõ bằng cách sử dụng DateTime? thay vì Nullable <DateTime>.
Stewart Johnson

Câu trả lời:


325

Câu hỏi này đã được hỏi rất nhiều lần rồi. Trình biên dịch đang nói với bạn rằng nó không biết cách chuyển đổi nullthành a DateTime.

Giải pháp rất đơn giản:

DateTime? foo;
foo = true ? (DateTime?)null : new DateTime(0);

Lưu ý rằng Nullable<DateTime>có thể được viết DateTime?sẽ giúp bạn tiết kiệm một loạt các gõ.


Hoạt động đủ tốt nhưng bây giờ bạn không thể kiểm tra foo - nó sẽ luôn có giá trị. Mặc dù vậy, không có cách nào khác - như MojoFilter nói "Đó là bởi vì trong một toán tử ternary, hai giá trị phải cùng loại."
DilbertDave

@DilbertDave Thông tin từ bài đăng của MojoFilter là không chính xác.
Mishax

4
Tôi muốn thêm rằng trình biên dịch cố gắng đoán loại kết quả của hoạt động ternary không phải bằng cách nhìn vào biến được gán, mà bằng cách nhìn vào các toán hạng thay thế. Nó tìm thấy <null>DateTimethay vì tìm loại tổ tiên chung, nó chỉ cố gắng tìm một chuyển đổi giữa nhau. (Thêm bit: C # nhận ra một <null>loại, tức là loại của mọi nullbiểu thức.)
IllidanS4 muốn Monica quay lại vào

Nếu nó đã được hỏi rất nhiều lần rồi, cờ câu hỏi trùng lặp ở đâu?
starmandeluxe

@starmandeluxe tất cả đều có khả năng chỉ vào đây (ít nhất là tôi đã đến đây bằng cách nào)
Scott Chamberlain

19

FYI (Offtopic, nhưng tiện lợi và liên quan đến các loại nullable) chúng tôi có một toán tử tiện dụng chỉ dành cho các loại nullable được gọi là toán tử hợp nhất null

??

Được sử dụng như thế này:

// Left hand is the nullable type, righthand is default if the type is null.
Nullable<DateTime> foo;
DateTime value = foo ?? new DateTime(0);

9
Làm thế nào điều này trả lời câu hỏi của mình ??
Stewart Johnson

3
Nick đang cố gắng gán null cho foo nếu một số điều kiện là đúng. Sự kết hợp null sẽ gán DateTime (0) cho giá trị nếu foo là null. Hai người hoàn toàn không liên quan.
Jeromy Irvine

4
Do đó FYI, offtopic nhưng một điều tốt đẹp để biết.
FlySwat

À, được rồi Nó là khá hữu ích để biết.
Jeromy Irvine

8

Đó là bởi vì trong một toán tử ternary, hai giá trị phải phân giải thành cùng loại.


10
Không, họ không phải là cùng một loại. Toán hạng thứ hai phải được chuyển đổi hoàn toàn sang loại toán hạng thứ ba hoặc ngược lại.
Mishax

3

Tôi biết câu hỏi này đã được hỏi vào năm 2008 và bây giờ là 5 năm sau nhưng câu trả lời được đánh dấu là câu trả lời không làm tôi hài lòng. Câu trả lời thực sự là DateTime là một cấu trúc và vì là một cấu trúc nên nó không tương thích với null. Bạn có hai cách để giải quyết:

Đầu tiên là làm cho null tương thích với DateTime (ví dụ: chuyển null thành DateTime? Như quý ông với 70 gợi ý, hoặc chuyển null thành Object hoặc ValueType).

Thứ hai là làm cho DateTime tương thích với null (ví dụ: truyền DateTime thành DateTime?).


3

Một giải pháp khác tương tự như được chấp nhận là sử dụng defaulttừ khóa của C # . Trong khi được định nghĩa bằng cách sử dụng thuốc generic, nó thực sự có thể áp dụng cho bất kỳ loại nào.

Sử dụng ví dụ áp dụng cho câu hỏi của OP:

Nullable<DateTime> foo;
foo = true ? default(DateTime) : new DateTime(0);

Ví dụ sử dụng với câu trả lời được chấp nhận hiện tại:

DateTime? foo;
foo = true ? default(DateTime) : new DateTime(0);

Ngoài ra, bằng cách sử dụng default, bạn không cần chỉ định biến như nullableđể gán cho nó một nullgiá trị. Trình biên dịch sẽ tự động gán giá trị mặc định của loại biến cụ thể và không gặp phải lỗi nào. Thí dụ:

DateTime foo;
foo = true ? default(DateTime) : new DateTime(0);

13
Không đúng, default(DateTime)không phải là null, nó là " 1.1.0001 0:00:00", giống như new DateTime(0).
IllidanS4 muốn Monica trở lại vào

@ IllidanS4, tôi không nói rằng nó bằng null, chỉ bằng cách sử dụng default()bạn có thể gán nó cho một nullablegiá trị (như trạng thái MSDN). Các ví dụ tôi chỉ chứng minh tính linh hoạt mà nó có thể được sử dụng với Nullable<DateTime>, DateTime?và chỉ đơn giản DateTime. Nếu bạn tin rằng điều này là không chính xác, bạn có thể cung cấp PoC khi những lỗi này không?
newf thấty

3
Vâng, người hỏi muốn lưu trữ nulltrong biến, không default(DateTime), vì vậy điều này là sai lệch nhất. Điều này không "linh hoạt" như bạn ngụ ý, vì toàn bộ biểu thức vẫn có cùng loại - DateTimevà bạn có thể thay thế default(DateTime)bằng new DateTime()và nó sẽ làm điều tương tự. Có lẽ đó default(DateTime?)là những gì bạn muốn nói, vì điều đó thực sự bằng null.
IllidanS4 muốn Monica trở lại
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.