Thursday, March 19, 2015

C#: Default value for int? and other nullable types

If you’re a C# developer, you’re probably aware of the nullable versions of primitive types such as int. Just declare the variable with a question mark added to the type, like so:

int? i;

And presto, you have an int variable to which you can assign null!  Very handy for working with nullable number fields in databases, among other uses.

Before today, the above was pretty much the extent of my knowledge of C# nullable types.  As far as I was concerned, they were just “magic” versions of the corresponding primitives.

I ran into a situation today, though, that led me to investigate more deeply.  I had a class with a nullable type field for which no default value was explicitly assigned, as in this simplified example:

    Class MyClass
    {
         public int? I { get; set; }
    }

I needed to determine whether the field had been assigned a value other than the default value.  That led me to ask the question: What is the default value for an unassigned nullable int? instance variable in C#?  Is it null, like for reference types?  Or is it 0, like for int?

Surprisingly, searching Google didn’t immediately lead to a clear answer; nor did there seem to be a question on StackOverflow asking for this particular information.  The MSDN article Nullable Types (which was the first Google hit for terms C# nullable default value) didn’t have a clear answer.

It was the work of just a couple of minutes to write and run a bit of code to test the behavior using LINQPad.  The answer: The default value of a C# int? is null.

So int? defaults to null.  But why?

I was curious: Why is the default value null, not 0?  So I did some investigating, and ended up learning the following:

  • int? is syntactic sugar for the type Nullable<T> (where T is int), a struct.  (Per that Nullable Types MSDN article.)
  • The Nullable<T> type has a bool HasValue member, which when false, makes the Nullable<T> instance "act like" a null value.  In particular, the Nullable<T>.Equals method  is overridden to return true when a Nullable<T> with HasValue==false is compared with an actual null value.
  • From the C# Language Specification 11.3.4, a struct instance's initial default value is all of that struct's value type fields set to their default value, and all of that struct's reference type fields set to null. 
  • The default value of a bool variable in C# is false (reference). 

Therefore, the HasValue property of a default Nullable<T> instance is false; which in turn makes that Nullable<T> instance itself act like null.

Since there was no readily-available information on this topic in StackOverflow, I went ahead and posted it there as a new question and answer.

A null int? just simulates an actual null value

An interesting aspect of an int? merely “simulating” a null value, rather than actually being one, is that you can call methods on a null-value int? without a NullReferenceException occurring!  For example, this code using a null String throws a NullReferenceException:

    String s = null;
    s.GetHashCode(); // Throws NullReferenceException

The same code, though, used with a null Nullable<T>, does not throw an exception:

    int? n = null;
    n.GetHashCode(); // Returns 0

1 comment:

  1. Have you checked other nullables, such as user-defined structs and enums?
    ReSharper seems to think the default of a nullable enum is the default enum rather than null.

    ReplyDelete