tags:

views:

168

answers:

5

Consider the following code:

DateTime? ndate = null;
Console.WriteLine(ndate.HasValue);

I would have expected a NullReferenceException, but HasValue will indeed return false. However, since ndate is null, how does the property invocation succeed, since there is no object to invoke the property HasValue on?

A: 

Synctactic sugar my friend ... the compiler turns that .HasValue call into code that won't throw an exception :-)

Joel Martinez
Not really true - the ndate variable is technically never "null" since it's a value type, and cannot be null. It has a value of null, which is very different.
Reed Copsey
Actually, the compiler turns `ndate = null` into `ndate = new Nullable<DateTime>()`
Greg
+2  A: 

What really happens is that an actual (non-null) Nullable structure gets assigned to the variable, thus the variable is not null but it's Value is.

tvanfosson
Well... really, even its *value* isn't null, since `Nullable<T>` has a `where T : struct` constraint, right? I would assume it's just a flag on the inside.
Dan Tao
+5  A: 

The Nullable<T> is a struct, basically it can't hold a null value.

Your assignment, is actually compiled into something that looks like this:

Nullable<DateTime> ndate = new Nullable<DateTime>();

Another example, the expression:

int? a = null;

Will generate the following IL:

.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0)
IL_0000:  ldloca.s   V_0
IL_0002:  initobj    valuetype [mscorlib]System.Nullable`1<int32>

A call to the initobj operation, which initializes each field of the a value type at a specified address to a null reference or a 0 of the appropriate primitive type.

In conclusion, what's happening here is the default struct initialization.

CMS
+13  A: 

Technically, "ndate" is not null - it is a value type, with it's value specified as being null.

When you write DateTime?, this is just shorthand for Nullable<DateTime>, which is a struct. There is no way for this to technically be null, since it's not a reference type.

Reed Copsey
+1 best explanation.
JonH
I assume then that (ndate == null) works via an overloaded operator?
Nathan
@Nathan true 15 chars
JonH
@Nathan: Yes. The compiler just initailizes it to a new Nullable<T>, which is flagged null by default.
Reed Copsey
+3  A: 

I would have expected a NullReferenceException

There is no null reference being dereferenced, so "NullReferenceException" should not be expected. The nullable DateTime is not a null reference. It is a null value.

However, since ndate is null, how does the property invocation succeed, since there is no object to invoke the property HasValue on?

The question presupposes a false premise. There is an object. There's a nullable DateTime representing the null value of a nullable DateTime . That value is an object.

Consider your code:

DateTime? ndate = null; 
Console.WriteLine(ndate.HasValue); 

This is just a short way of writing something that is logically like:

DateTime ndate = default(DateTime); 
bool ndateHasValue = false;
Console.WriteLine(ndateHasValue); 

A nullable value type is simply a pleasant way to write code that means "please attach a Boolean to this thing that keeps track of whether it is logically null or not".

Eric Lippert