You may want to read Eric Gunnerson's article about boxing.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp03152001.asp
<From the article>
Consider the following code:
int value = 123;
object o = value; // box int into an object box
int value2 = (int) o; // unbox into value2
When value is assigned to o, as part of the assignment the C# compiler
creates a reference-type box big enough to hold the int on the heap, copies
the value to that box, then marks the box with the actual type (System.Int32
in this case) so the runtime knows what type is in the box
To get a value out of a box, we must specify what type we think is in the
box (since object can hold any type) with a cast. During execution, the
runtime will check whether the type that the object variable refers to is
the type specified in the cast. If the type is correct, the value will be
copied from the box back to the value type variable. If the type is
incorrect, an exception will be thrown.
Note that no other conversions can happen as part of the unboxing operation;
the types must match exactly. In other words, if we write:
long value2 = (long) o; // boxed value is an int
and o is a boxed int, an exception will be thrown. We can, however, write:
long value2 = (long)(int) o;
and the conversion will work as expected.