TechQuiz Question 3: Nullable boxing

Why does Foo<int?> throw an exception?

   1:  static void Foo<T>() where T : new()
   2:  {
   3:      T t = new T();
   4:      Console.WriteLine("ToString: " + t.ToString()); 
   5:      Console.WriteLine("GetHashCode: " + t.GetHashCode()); 
   6:      Console.WriteLine("Equals: " + t.Equals(t)); 
   7:      Console.WriteLine("GetType: " + t.GetType());
   8:  }
   9:   
  10:  public void Main()
  11:  {
  12:      Foo<int>();
  13:      Foo<int?>(); // Exception thrown
  14:  }
 

Answer

int? is a nullable type. T t = new T(); returns a Nullable<int> with a value of 
null. If we have a look at the definition of Nullable<T> we find the following:

   1:  [Serializable]
   2:  public struct Nullable<T> where T : struct
   3:  {
   4:      public Nullable(T value);
   5:   
   6:      public static explicit operator T(Nullable<T> value);
   7:      public static implicit operator Nullable<T>(T value);
   8:   
   9:      public bool HasValue { get; }
  10:      public T Value { get; }
  11:   
  12:      public override bool Equals(object other);
  13:      public override int GetHashCode();
  14:      public T GetValueOrDefault();
  15:      public T GetValueOrDefault(T defaultValue);
  16:      public override string ToString();
  17:  }

As you can see, Nullable<T> overrides ToString, GetHashCode and Equals. Calling these methods on a nullable type is save will give you a nice result.

But GetType is another story. GetType only exists on the base class Object and cannot be overridden. When calling GetType on a Nullable<T>, your item is boxed to Object.

   1:  int i = 123;
   2:  // The following line boxes i.
   3:  object o = i;  

If you have a Nullable<T> with a value of null and you box it to object you get null 
back. Think of it like having a null value being boxed to a null reference. And calling GetType() on null gives you an exception!

Leave a Reply

Your email address will not be published. Required fields are marked *