There is plenty of information about Nullable<T> type out there and how to use it. There are, however a few tidbits that are not quite as obvious at first glance.

#Nullable is a value type

It’s a struct that can be null. The only reason why int? intVal = null; compiles is because C# compiler supports nullable types. You cannot define the same kind of struct yourself.

The decision to make Nullable<T> a value type actually makes sense if you think about it. Calling its member methods and properties will always succeed, i.e. NullReferenceException will never be thrown. This gurantees that HasValue never throws a NullReferenceException.

#Comparison to null

Under the hood, the compiler, in fact translates comparison to null to a call to HasValue. The below MSIL demonstrates that:

	.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> 'value',
		   [1] bool hasvalue,
		   [2] bool hasvalue2)

	//int? value = null;
	IL_0001:  ldloca.s   'value'
	IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
	//bool hasvalue = value.HasValue;
	IL_0009:  ldloca.s   'value'
	IL_000b:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
	IL_0010:  stloc.1
	//bool hasvalue2 = value != null;
	IL_0011:  ldloca.s   'value' //loads a variable onto evaluation stack
	IL_0013:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue() //calls HasValue
	IL_001b:  stloc.2 //Stores the result in location 2 (hasvalue2)

As you can see the generated IL for hasvalue = value.HasValue and hasvalue2 = value != null are identical.

#null Assignment

Also from above code you can see that assigning null to a nullable value is the same as calling the parameterless contructor (which all value types have).

#Ternary operator

C# compiler also does special things with ternary operator for nullable types. The following code compiles:

int? nullableIntVal = 4;
int intVal = nullableIntVal ?? -1;

The above is just syntactic sugar for calling HasValue and if it’s true calling GetValueOrDefault(). The compiler actually generates a temporary variable to call HasValue off in both Release and Debug modes. Not sure why that is. Below code illustrates the equivalent C# code to what the compiler generates for ternary operator.

int? nullableIntVal = 4;
int? temp = nullableIntVal;
int intVal = temp.HasValue ?? temp.GetValueOrDefault() : -1;

#Summary

Nullable<T> is a special value type that has support from C# compiler to allow the following:

  • null assignment - under the hood: calling defualt constructor.
  • null comparison - under the hood: calling HasValue property.
  • ternary operator ?? - under the hood: calling HasValue and conditionally GetValueOrDefault.


blog comments powered by Disqus

Published

29 May 2010

Tags