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.
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 ( valuetype [mscorlib]System.Nullable`1<int32> 'value',  bool hasvalue,  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.
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).
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;
Nullable<T> is a special value type that has support from C# compiler to allow the following:
nullassignment – under the hood: calling defualt constructor.
nullcomparison – under the hood: calling
- ternary operator
??– under the hood: calling