2009-03-27 21 views
33

Tại sao nó không được phép gán null vào một DateTime trong C#? Làm thế nào điều này đã được thực hiện? Và tính năng này có thể được sử dụng để làm cho các lớp của riêng bạn không nullable?Tại sao null không được phép cho DateTime trong C#?

Ví dụ:

string stringTest = null; // Okay 
DateTime dateTimeTest = null; // Compile error 

tôi biết rằng tôi có thể sử dụng DateTime? trong C# 2.0 cho phép null để được giao cho dateTimeTest và rằng tôi có thể sử dụng Jon Skeet's NonNullable class trên chuỗi của tôi để nhận được một lỗi thời gian chạy trên giao stringTest. Tôi chỉ tự hỏi tại sao hai loại này lại hoạt động khác nhau.

+0

Jon không phải là John. –

Trả lời

76

DateTime là loại giá trị (struct), trong đó chuỗi là loại tham chiếu (class v.v.). Đó là điểm khác biệt chính. Một tham chiếu luôn có thể là null; một giá trị không thể (trừ khi nó sử dụng Nullable<T> - tức là DateTime?), mặc dù nó có thể là 0 (DateTime.MinValue), thường được hiểu là giống như null (đặc biệt trong 1,1).

+0

Cảm ơn rất nhiều vì đã làm rõ. Tại sao không sử dụng cấu trúc để tạo ra các lớp không nullable? –

+1

Và những gì sẽ mặc định (YourWrapper) được? ;-p Nó sẽ là một struct chứa tham chiếu null ... tất cả các struct * luôn luôn * có một constructor mặc định ... –

+0

(hoặc * never * có một constructor mặc định, tùy thuộc vào việc bạn đang nói về C# hay CLI - mà không đồng ý về điểm này) –

8

DateTime là cấu trúc chứ không phải lớp. Làm một 'đi đến định nghĩa' hoặc nhìn vào nó trong trình duyệt đối tượng để xem.

HTH!

1

DateTime là một loại giá trị, giống như một int. Chỉ các loại tham chiếu (như chuỗi hoặc MyCustomObject) mới có thể rỗng. Các loại tham chiếu thực sự lưu trữ "tham chiếu" đến vị trí của đối tượng trên heap.

đây là số article Tôi thấy rằng giải thích tốt hơn. và đây là số MSDN article on it

+0

Hoặc các loại giá trị có thể vô hiệu hóa qua Nullable (cũng chính là cấu trúc) –

0

chuỗi là một lớp trong khi DateTime là cấu trúc. Đó là lý do tại sao bạn không thể đặt nó thành null

7

Sự khác biệt quan trọng giữa ValueTypes và loại tham chiếu là các loại giá trị có "ngữ nghĩa giá trị" này. Một DateTime, Int32 và tất cả các loại giá trị khác không có bản sắc, Int32 "42" về cơ bản không phân biệt được với bất kỳ Int32 nào khác có cùng giá trị.

Tất cả loại giá trị "đối tượng" tồn tại trên ngăn xếp hoặc là một phần của đối tượng loại tham chiếu. Một trường hợp đặc biệt là khi bạn tạo một thể hiện kiểu giá trị cho một đối tượng hoặc một giao diện - điều này được gọi là "boxing" và nó chỉ đơn giản là tạo một đối tượng kiểu tham chiếu giả mà chỉ chứa giá trị có thể được trích xuất lại ("unboxed") .

Các loại tham chiếu, mặt khác, có một danh tính. một "đối tượng mới()" không bằng bất kỳ "đối tượng mới" nào khác, bởi vì chúng là các cá thể riêng biệt trên vùng đệm GC. Một số kiểu tham chiếu cung cấp phương thức Equals và các toán tử quá tải để chúng hoạt động giống như giá trị hơn, ví dụ. một chuỗi "abc" bằng chuỗi "abc" khác ngay cả khi chúng có hai thực thể khác nhau.

Vì vậy, khi bạn có tham chiếu, nó có thể chứa địa chỉ của đối tượng hợp lệ hoặc có thể là rỗng. Khi các đối tượng kiểu giá trị là tất cả bằng không, chúng đơn giản là không. Ví dụ. một số nguyên không, một số không float, Boolean false hoặc DateTime.MinValue. Nếu bạn cần phân biệt giữa "không" và "giá trị thiếu/null", bạn cần sử dụng cờ Boolean riêng biệt hoặc tốt hơn, hãy sử dụng lớp Nullable < T> trong .NET 2.0. Đơn giản chỉ là giá trị cộng với cờ Boolean. Ngoài ra còn có sự hỗ trợ trong CLR để boxing của Nullable với HasValue = false kết quả trong một tham chiếu null, không phải trong một cấu trúc đóng hộp với false + zero, vì nó sẽ nếu bạn đã thực hiện cấu trúc này cho mình.

1

Đối với một loại giá trị rỗng, phải có một số giá trị có thể giữ mà không có ý nghĩa hợp pháp nào khác và mà hệ thống sẽ biết được coi là "null". Một số loại giá trị có thể đáp ứng tiêu chí đầu tiên mà không yêu cầu bất kỳ bộ nhớ bổ sung nào. Nếu .net đã được thiết kế từ mặt đất lên với các khái niệm về giá trị nullable trong tâm trí, nó có thể đã Object include a virtual IsLogicalNull property, and a non-virtual IsNull which would return đúng if này is null and, otherwise invoke its IsLogicalNull property and return the result. If .net had done this, it would have avoided the need for the quirky boxing behavior and struct constraint of Nullable (an empty Nullable could be boxed as an empty Nullable , and still be recognized as null`).

Vào thời điểm nó được quyết định cung cấp sự hỗ trợ cho các loại giá trị nullable trong .net 2.0, tuy nhiên, rất nhiều mã đã được viết trong đó giả định rằng các giá trị mặc định cho những thứ như GuidDateTime sẽ không được coi là null. Vì nhiều giá trị trong các loại có thể đặt giá trị nằm trong giá trị mặc định có thể dự đoán của chúng (ví dụ: null), có các loại có giá trị null, nhưng được đặt mặc định thành giá trị khác, sẽ gây nhầm lẫn nhiều hơn giá trị.