2016-01-29 19 views
29

Như bạn đã biết, DateTime? không có parametrized ToString (đối với mục đích của định dạng đầu ra), và làm một cái gì đó giống nhưLiệu "?". toán tử làm bất cứ điều gì khác ngoài việc kiểm tra null?

DateTime? dt = DateTime.Now; 
string x; 
if(dt != null) 
    x = dt.ToString("dd/MM/yyyy"); 

sẽ ném

Không quá tải cho phương pháp 'ToString' mất 1 đối số

Tuy nhiên, vì C# 6.0 và toán tử Elvis (?.), mã trên có thể được thay thế bằng

x = dt?.ToString("dd/MM/yyyy"); 

mà .... hoạt động! Tại sao?

+1

Sau khi đọc câu trả lời, tôi không thể giúp đỡ, nhưng cảm thấy rằng các giải pháp thực tế cho vấn đề của mình đi như thế, "Chỉ cần sử dụng' dt.Value.ToString() 'đã có" –

+0

Nếu dt là null thì sao? –

+0

Ya, chỉ cần gọi dt.Value.ToString() sẽ phát sinh nếu dt là null; bạn chắc chắn muốn sử dụng toán tử Elvis, không chỉ vì nó có tên tuyệt vời mà còn vì nó xử lý việc kiểm tra NULL cho bạn. dt? .Value.ToString() về cơ bản nói "Nếu dt không rỗng, thì truy cập thuộc tính Value và chuyển nó thành String; nếu nó IS null, bỏ qua cuộc gọi và không làm gì" –

Trả lời

20

Bởi vì Nullable<T> được triển khai trong C# theo cách làm cho các phiên bản của cấu trúc đó xuất hiện dưới dạng các loại có thể null. Khi bạn có DateTime? nó thực sự Nullable<DateTime>, khi bạn gán null vào đó, bạn đang thiết HasValue-false đằng sau hậu trường, khi bạn kiểm tra null, bạn đang kiểm tra cho HasValue vv Các nhà điều hành ?. chỉ được thực hiện một cách nó thay thế các thành ngữ rất giống nhau làm việc cho các kiểu tham chiếu cũng cho các cấu trúc rỗng. Cũng giống như phần còn lại của ngôn ngữ làm cho cấu trúc nullable tương tự như các loại tài liệu tham khảo (liên quan đến null -ness).

14

Câu trả lời ngắn:

DateTime? chỉ là một cú pháp ngọt ngào cho Nullable<DateTime> mà không chứa DateTime 's thuộc tính và phương thức trong khi các nhà điều hành Elvis hoạt động trên không-Nullable Nullable<DateTime>.Value.


Giải thích:

Các mã sau đây:

DateTime? dt = DateTime.Now; 
string x; 
if (dt != null) 
    x = dt?.ToString("dd/MM/yyyy"); 

Khi dịch ngược như C# 5.0 mang lại kết quả sau:

DateTime? nullable = new DateTime?(DateTime.Now); 
if (nullable.HasValue) 
{ 
    string str = nullable.HasValue ? nullable.GetValueOrDefault().ToString("dd/MM/yyyy") : null; 
} 

Side lưu ý: string dường như tuyên bố bên trong if là không thích hợp vì cẩu ở cấp MSIL, và vì giá trị không được sử dụng sau trên decompiler cho thấy nó như thể nó đã được công bố bên trong phạm vi if.

Như bạn thấy, và kể từ DateTime? chỉ là một cú pháp ngọt ngào cho Nullable<DateTime>, C# có một tham chiếu cụ thể cho Nullable<T> s với các nhà điều hành Elvis, làm cho giá trị trả về của nó T không nullable tự .

Kết quả của toàn bộ Elvis operator phải Nullable do đó, nếu bạn muốn nhận được một string giá trị phi nó sẽ phải là một trong hai Nullable<T> hoặc một ReferenceType nhưng điều này không làm thay đổi thực tế rằng nếu nhà điều hành đã tự quản lý để tự nhận được giá trị Nullable<DateTime> - số trả lại DateTime không còn là Nullable<DateTime> nữa.

+4

Cử tri xuống xin giải thích để tôi có thể cải thiện câu trả lời của mình. –

+0

bạn nên xóa 'if' xung quanh việc gán chuỗi. Nó phủ nhận toán tử ternary bên trong. –

+0

Không, vì 'chuỗi' không được sử dụng sau này, đây là tối ưu hóa trình biên dịch. Đây là mã giải mã thực tế trong phản xạ ... –

2

Xét:

DateTime? dt = DateTime.Now; 
string x; 
if(dt != null) 
    x = dt.ToString("dd/MM/yyyy"); 

Dưới đây là một dtDateTime? hoặc Nullable<DateTime> phù thủy không phải là IFormatable và không có một phương pháp ToString(string format).

Vì vậy, nó ném.

Bây giờ xem xét:

x = dt?.ToString("dd/MM/yyyy"); 

Các ?. là một cú pháp đường cho:

dt.HasValue ? dt.Value.ToString("dd/MM/yyyy"): null 

Đây dt.Value là một phù thủy DateTime được IFormatable và có một phương pháp ToString(string format).

Cuối cùng cách tốt để viết mã đầu tiên trong C# 5.0 là:

DateTime? dt = DateTime.Now; 
string x; 
if(dt.HasValue) 
    x = dt.Value.ToString("dd/MM/yyyy"); 
Các vấn đề liên quan