Friday, October 24, 2008

How to make a non-nullable type wrapper in C#, today…

The Story of Nothing, in Arizona
Image by cobalt123 via Flickr

I was reading up on the development on Spec# and at the same time trying to figure out if we would start to see Spec# features in C#, anytime soon… Unfortunately, I don’t think we will find any Spec# features in C# 4.0, but I hope the team will prove me wrong.

If you haven’t looked at Spec# yet I strongly encourage you to take a look at it. The short story is that it is a research project which focuses on adding contract oriented constructs to the C# language. You can read more about it at the Spec# homepage or watch the Spec# introduction video on Channel9 which shows off some of the very cool features contract oriented programming brings to the table.

One of the features of Spec# is non-nullable types which is a type wrapper for reference types, sort of like the Nullable<T> type we got in C# 2.0 for value types, but with opposite meaning. In Spec# non-null types can be written as “object!”.

When a type is wrapped with the non-nullable type it can never be set to null. I hope you are now starting to think; “Cool, that would be a nice feature to have in C#”… If you are not, let me explain why you should.

Imagine a world where you could avoid writing code like this:

public void DoStuff(object input)
{
  if (input == null)
    throw new ArgumentNullException("input");

  // Method implementation...
}

Instead you could let the language and the compiler do the null checks for you. If you are a developer by profession, think back on all the applications you’ve made and think of all the null-checking code you’ve written that you could’ve avoided if you had the non-null type feature. Or better yet, think of all the null-checks you forgot to write and you then later discovered when a tester or customer reported an error that turned out to be a null reference exception. Ahh yes, those were the days, right?

Now, since we don’t expect Spec# features in C# anytime soon is there any way we might be able to implement this functionality with what we have? How would we go about writing a non-null type in C#? Well, a good place to start is to fire up reflector and look at how the Nullable<T> type is implemented. After doing that and looking at Jon Skeet’s proposal, I came up with the following slightly modified code:

public struct NonNull<T> where T : class
{
  private readonly T _value;
  public T Value { get { return _value; } }

  public NonNull(T instance)
  {
    if (instance == null)
    throw new ArgumentNullException("instance", "The \"instance\" parameter must not be null.");

    _value = instance;
  }

  public override int GetHashCode()
  {
    return _value.GetHashCode();
  }

  public override bool Equals(object obj)
  {
    return _value.Equals(obj);
  }

  public static bool operator ==(NonNull<T> valueA, NonNull<T> valueB)
  {
    return valueA._value == valueB._value;
  }

  public static bool operator !=(NonNull<T> valueA, NonNull<T> valueB)
  {
    return valueA._value != valueB._value;
  }

  public static implicit operator NonNull<T>(T value)
  {
    return new NonNull<T>(value);
  }

  public static explicit operator T(NonNull<T> value)
  {
    return value._value;
  }
}

But as Jon points out in his excellent blog post that would cause a big problem, since a struct always adds a default parameter-less constructor (that you can’t directly customize) it would be possible to instantiate a NonNull variable with the empty constructor, and thus let the non-null type contain a null value which it clearly shouldn’t. Jon solved this problem by putting a null check in the getter of the “Value” property but this would still hide a potential null reference error till pretty late in a runtime flow. The good news is I found a different solution.

After doing some research I found out that MSIL doesn’t require a default empty constructor to be empty. I then simply compiled a version of the code that had an extra constructor with a dummy parameter and then deleted the parameter from the compiled assembly using the awesome Reflexil plug-in for reflector. And presto, one nice little generic NonNull type wrapper was born. The final code used for this type was:

public struct NonNull<T> where T : class
{
  private readonly T _value;
  public T Value { get { return _value; } }

  [Obsolete("The default parameterless constructor has been disabled please use NonNull<T>(T instance) constructor instead.", true)]
  public NonNull(object dummy)
  {
    throw new NotSupportedException("The default parameterless constructor has been disabled please use NonNull<T>(T instance) constructor instead.");
  }

  public NonNull(T instance)
  {
    if (instance == null)
    throw new ArgumentNullException("instance", "The \"instance\" parameter must not be null.");

    _value = instance;
  }

  public override int GetHashCode()
  {
    return _value.GetHashCode();
  }

  public override bool Equals(object obj)
  {
    return _value.Equals(obj);
  }

  public static bool operator ==(NonNull<T> valueA, NonNull<T> valueB)
  {
    return valueA._value == valueB._value;
  }

  public static bool operator !=(NonNull<T> valueA, NonNull<T> valueB)
  {
    return valueA._value != valueB._value;
  }

  public static implicit operator NonNull<T>(T value)
  {
    return new NonNull<T>(value);
  }

  public static explicit operator T(NonNull<T> value)
  {
    return value._value;
  }
}

As you can see I opted to mark the default constructor as obsolete because that gives a nice little compile-time error if it’s used. I’m also throwing a NotSupportedException from the constructor if it happens to be executed by reflection. I realize that this class isn’t as user-friendly as you would like it to be, but for now it’s probably the closest we’ll get without help from the C# language team.

If you would like to try it out you can get a precompiled NonNull type here. Enjoy!

0 comments:

Post a Comment