40

Why it is not allowed to assign null to a DateTime in C#? How has this been implemented? And can this feature be used to make your own classes non-nullable?

Example:

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

I know that I can use DateTime? in C# 2.0 to allow null to be assigned to dateTimeTest and that I could use Jon Skeet's NonNullable class on my string to get a run time error on the assignment of stringTest. I'm just wondering why the two types behave differently.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Jan Aagaard
  • 10,940
  • 8
  • 45
  • 80

6 Answers6

89

DateTime is a value-type (struct), where-as string is a reference-type (class etc). That is the key difference. A reference can always be null; a value can't (unless it uses Nullable<T> - i.e. DateTime?), although it can be zero'd (DateTime.MinValue), which is often interpreted as the same thing as null (esp. in 1.1).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks a lot for the clarification. Why not use structs to make non-nullable classes? – Jan Aagaard Mar 27 '09 at 12:21
  • 1
    And what would default(YourWrapper) be? ;-p It would be a struct containing a null reference... all structs *always* have a default constructor... – Marc Gravell Mar 27 '09 at 12:22
  • (or *never* have a default constructor, depending on whether you are talking about C# or the CLI - which disagree over this point) – Marc Gravell Mar 27 '09 at 12:23
  • Marc, your answers are simply great. Concise and to the point! – Cherian Mar 27 '09 at 12:34
  • Thanks for suggesting the MinValue usage, I was looking for something to return from a method in the event that a value was not found. Exactly what I needed! – BMB Dec 13 '12 at 06:52
9

DateTime is a struct and not a class. Do a 'go to definition' or look at it in the object browser to see.

HTH!

Simon
  • 984
  • 1
  • 8
  • 24
7

The important distinction between ValueTypes and reference types is that value types have these "value semantics". A DateTime, Int32 and all other value types have no identity, an Int32 "42" is essentially indistinguishable from any other Int32 with the same value.

All value type "objects" exist either on stack or as a part of a reference type object. One special case is when you cast a value type instance to an Object or an interface - this is called "boxing", and it simply creates a dummy reference-type object which only contains the value that can be extracted back ("unboxed").

Reference types, on the other hand, have an identity. a "new Object()" does not equal any other "new Object()", because they are separate instances on the GC heap. Some reference types provide Equals method and overloaded operators so that they behave more value-like, eg. a String "abc" equals other "abc" String even if they are in fact two different objects.

So when you have a reference, it can either contain the address of a valid object, or it can be null. When value type objects are all-zero, they are simply zero. Eg. an integer zero, a float zero, Boolean false, or DateTime.MinValue. If you need to distinguish between "zero" and "value missing/null", you need to use either a separate Boolean flag, or, better yet, use the Nullable<T> class in .NET 2.0. Which is simply the value plus a Boolean flag. There's also support in the CLR so that boxing of a Nullable with HasValue=false results in a null reference, not in a boxed structure with false+zero, as it would if you were to implement this structure yourself.

1

For a value-type to be null, there must be some value it can hold which would have no other legitimate meaning, and which the system will somehow know should be regarded as "null". Some value types could meet the first criterion without requiring any extra storage. If .net had been designed from the ground up with the concept of nullable values in mind, it could have had Object include a virtualIsLogicalNullproperty, and a non-virtualIsNullwhich would returntrueifthisis null and, otherwise invoke itsIsLogicalNullproperty and return the result. If .net had done this, it would have avoided the need for the quirky boxing behavior andstructconstraint ofNullable(an emptyNullablecould be boxed as an emptyNullable, and still be recognized asnull`).

By the time it was decided to provide support for nullable value types in .net framework 2.0, however, a lot of code had been written which assumed that the default values for things like Guid and DateTime would not be regarded as null. Since much of the value in nullable types lies with their predictable default value (i.e. null) , having types which had a null value, but defaulted to something else, would have added more confusion than value.

Anirudha Gupta
  • 9,073
  • 9
  • 54
  • 79
supercat
  • 77,689
  • 9
  • 166
  • 211
1

DateTime is a value type, same as an int. Only reference types (like string or MyCustomObject) can be null. Reference types really store "references" to the objects location on the heap.

here's a article I found that explains it better. and here's the MSDN article on it

danswain
  • 4,171
  • 5
  • 37
  • 43
0

string is a class whereas DateTime is a structure. Thats why you cannot set it to null

Rob Haupt
  • 2,104
  • 1
  • 15
  • 24