C Sharp

Boxing and Unboxing

So, the question becomes, "How do these different categories of types make the system more efficient?" This is done through the magic of boxing. At its simplest, boxing is the conversion of a value type to a reference type. The reciprocal case is when a reference type is unboxed back to a value type.

What makes this technique so great is that an object is only an object when it needs to be. For example, let's say you declare a value type such as System.Int32. Memory for this variableis allocatedfrom the stack. You can pass this variable to any method defined as taking a System.Object type, and you access any of its members for which you have access. Therefore, to you it looks and feels just like an object. However, in reality, it's just four bytes on the stack.

It's only when you attempt to use that variable in a way consistent with its implied System.Object base class interface that the system automatically boxes the variable so that it becomes a reference type and can be used like any object. Boxing is how C# enables everything to appear to be an object, thereby avoiding the overhead required if everything actually were an object. Let's look at some examples to bring this into focus.

int foo = 42;         // Value type.
object bar = foo;     // foo is boxed to bar.

In the first line of this code, we're creating a variable (foo)of type int. As you know, the type int is a value type (because it's a primitive type). In the second line, the compiler sees that the variable foo is being copied to a reference type, which is represented by the variable bar. The compiler then spits out the MSIL code necessary to box this value.

Now, to convert bar back to a value type, you can perform an explicit cast: -

int foo = 42;         // Value type.
object bar = foo;     // foo is boxed to bar.
int foo2 = (int)bar;  // Unboxed back to int.

Notice that when boxing-that is, once again, when converting from a value type to a reference type-there is no explicit cast needed. However, when unboxing-converting from a reference type to a value type-the cast is needed. This is because in the case of unboxing, an object could be cast to any type. Therefore, the cast is necessary so that the compiler can verify that the cast is valid per the specified variable type. Because casting involves strict rules and because these rules are governed by the CTS, we'll take a look at this issue in more detail later in this chapter in "Casting Between Types." -