May 31

.NET and nullable value types – part III

Posted in Uncategorized      Comments Off on .NET and nullable value types – part III

As you’ve probably noticed, I’ve been a little busy with my new cat. Besides that, I’ve also caught a cold and I’m still lagging in my last work project. Nonetheless, I need to relax and I guess that writing another post on the .NET and nullable value type series is a good way to let off some steam…what can I say? 🙂

In the previous post of the series, we’ve seen how C# simplifies the code needed for working with nullable value types (ie, with the Nullable<T> type). If you’ve been using nullable value types, you’ve probably noticed that they don´t really behave like a “normal” value types. This is only possible because the CLR understands that nullable value types are “special” types and gives them special treatment. Here’s a small example:

Int32? aux = 5;
Console.WriteLine( aux.GetType(  ) );//what does this print?

So, what should the previous snippet print? Int32? Nullable<Int32>? Well, the truth is that Nullable<T> lies and returns Int32 (instead of Nullable<Int32>). This is just one example that shows that Nullable<T> does, in fact, enjoy special treatment from the CLR…but there’s more:

Int32? aux = 5;
Object someA = aux;
Console.WriteLine( someA );
Console.WriteLine( someA.GetType(  ) );

In the previous snippet, we’re initializing someA (which is an object) with aux (nullable value type). If you recall our previous discussions, you’ll remember that putting a value type into an object will always result in a boxing operation. And that’s exactly what is going on here. When the CLR notices that the nullable value type does, indeed, hold a value, it will automatically box that value. When that doesn’t happen (ie, when aux.HasValue returns false), then the CLR won’t do a thing and someA’s value  will be set to null. Grovy, right?

Int32? aux = null;
Object someA = aux;//someA is null; NO boxing

If the CLR can box a nullable value type, then it also needs to perform the reverse operation. In practice, you can unbox a previously boxed T into T or into a Nullable<T> value:

Int32? aux = null;
Object someA = aux;//someA is null; NO boxing
Int32? unboxed1 = (Int32?)someA;//no value
Int32? unboxed2 = ( Int32 )someA;//throws

As you can see, unboxing will throw whenever you attempt to convert it to T. That won’t happen when you use T? (ie, Nullable<T>) because we’ve already seen that it’s possible to initialize T? with null. What about interfaces? For instance, if you look at the Int32 type, you’ll quickly notice that it implements the IComparable interface (explicitly). What happens when you need to work to work directly with that interface? For instance, should the following code work?

static void DoSomething(IComparable comparable){}
static void Main(string[] args) {
    Int32? aux = 5;
    DoSomething( aux );

aux is  a Nullable<Int32> instance and Nullable<T> does not implement the IComparable interface. But Int32 does. If there were no special support from the C# compiler and from the CLR, that would mean that the previous code would, at least, need to perform an explicit cast to Int32 (or access the aux.Value directly). In other words, it would make working with nullable value types a little more cumbersome.

These special support form the CLR makes using nullable value types easy and transparent. And this makes me a happier person…it does…and that’s all for now. Stay tuned for more.