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