Pandora’s Unbox (and conversions)
As Pandora, a C#/.NET developer should be familiar with the concepts of “boxing” and “unboxing” of .NET types (although Pandora may have not been familiar with the boxing part). As a reminder take a look at the following statements:
int i = 1234; object o = i; // Box System.Console.WriteLine(o.GetType()); // Will display System.Int32 int j = (int)o; // Unbox System.Console.WriteLine(j); // Will display 1234
In the snippet above we’ve created and assigned a variable of type int (System.Int32) and straight after “boxed-it” into an object variable again via assignment. I believe the .NET definition of “to-box” is to convert to a reference type from a value type. Proof that indeed our object variable is now of type System.Int32 is shown. We’ve then “unboxed” it back into an int-typed variable; definition of “to-unbox” to convert from reference type to value type. Notice the necessary explicit (int) type cast.
Now, ponder on the following statements:
object o = 1234; // Box an int
System.Console.WriteLine(o.GetType()); // Will display System.Int32
short h = (short)o; // Unbox. Throws InvalidCastException at runtime.
What we’ve done is created and assigned implicitly a direct literal value to a variable of type System.Object. This is perfectly legal and behind the scenes the CLR will automatically box it as a System.Int32 type. We’ll print out the runtime type just to be sure. Straight after, we’ll unbox the value, however this time to a short-typed (System.Int16) variable. Surely this could be possible, especially if the value we want to assign fits into the range of the short. But although the snippet above compiles, you’ll be surprised to see a runtime exception of an InvalidCastException. However, if the offending line looked like this:
short h = (short)(int)o; // Unbox and convert?
// Always explicitly unbox the runtime type first,
// then cast to desired type.
It would work perfectly! Here’s another example:
byte b = 123;object o = b; // Box a byte into the object.
System.Console.WriteLine(o.GetType()); // Will display System.Byte
short h = (short)(byte)o; // Unbox and convert?
// Always explicitly unbox the runtime type first,
// then cast to desired type.
So, although the CLR already knows the type of your boxed contents in your object-typed variables, you have to explicitly cast to the runtime type during your unboxing operations before performing any further conversions.
The 15-thousand dollar question would be now, what if you don’t know what the original type is? Obviously in runtime you can get to it as we’ve seen with the displaying of o.GetType(), but how do you unbox your object without explicitly defining it during code authoring? The answer is, by using utility classes like the static Convert class. With this class you can simply do:
object o = 1234; // Box an int
int i = Convert.ToInt32(o); // Just unbox it.
short h = Convert.ToInt16(o); // Unbox and convert it to a short.
double d = Convert.ToDouble(o); // Unbox and convert to a double.
string s = Convert.ToString(o); // Unbox and convert it to a string.
and so on…
In fact, you can convert to just about anything without worrying about the details. The Convert class basically performs a set of unboxing teqniques like described above, however the key point is that it provides numerous overloads of the said methods and therefore the runtime automatically calls the correct one and then works its unboxing and conversion magic based on the method’s input parameter. For instance, in the above case:
object o = 1234; // Box an int
short h = Convert.ToInt16(o); // Will call Convert.ToInt16(object value) overload.
You could also take advantage of simple value type’s IConvertible methods that have been provided for the reasons of converting from one type to another. So, in our case, we could also do:
object o = 1234; // Box an int
short h = ((IConvertible)o).ToInt16(null); // Unbox and convert our object from whatever
// it is to an Int16. Providing of course it’s
// one of C#’s value types or string.
In fact, that’s exactly what the Convert utility methods do behind the scenes when working with implicit types!
Now, obviously writing code like the above is not ideal. There’s so many things that could go wrong; although using Convert is much more sound as it does perform validation. However in most cases, you should not ever have to explicitly cast one type to another, especially with powerful language features like Generics and Type Inference and other OOP techniques, but from the standpoint of performance; just as importantly. To be honest, this is rather reminiscing of the Zen of early languages. However, you’ll be surprised just how many C# screening sheets today drivel down snippets like the said. It’s always useful knowing a rule of thumb… or two.