#1,062 – Unboxing Conversions

If you’ve converted a value-typed object to a reference-typed object by boxing it, you can later unbox the object, converting it back to a value type.  Unboxing is an explicit conversion and requires a cast operator.

Below are some examples of unboxing conversions.

        public interface IArea
        {
            double CalcArea();
        }

        public struct MyPoint : IArea
        {
            public double X;
            public double Y;

            public MyPoint(double x, double y)
            {
                X = x;
                Y = y;
            }

            public double CalcArea()
            {
                return X * Y;
            }
        }

        static void Main(string[] args)
        {
            int i1 = 12;
            object o = i1;  // Boxing - implicit

            // Unbox from object to value type
            int i2 = (int)o;  // Boxing - explicit conversion

            // Unbox from dynamic
            dynamic d = i1;
            int i3 = (int)d;

            // Boxing, implicit, creates new copy
            MyPoint pt = new MyPoint(2.0, 3.0);
            IArea area = pt;

            // Unboxing, explicit,
            // from interface to value type,
            // creates new copy again
            MyPoint pt2 = (MyPoint)area;

            // Unbox to nullable type
            int? i4 = (int?)o;
            o = null;
            int? i5 = (int?)o;  // also works

            // Boxing, implicit, to ValueType
            // (creates copy)
            ValueType vty = pt;

            // Unboxing, creates copy
            MyPoint pt3 = (MyPoint)vty;
        }

#658 – What Boxing and Unboxing Look Like in IL

Recall that your C# source code is compiled to a platform-neutral intermediate language called Common Intermediate Language.  You can view the IL for your application, after building the code, using the IL Disassembler tool.

If you look at the IL generated for code that boxes or unboxes a value, you’ll see unique CIL instructions for boxing (box) and unboxing (unbox).

Assume that you box an int value and then later unbox it.

int x = 12;

object o = x;    // Box

int y = (int)o;  // Unbox

If you build this code and look at the IL, you’ll see the box and unbox instructions.

#221 – When Unboxing, You Must Match the Original Type Exactly

We know that we can do explicit casts when assigning from one type to another and the assignment will work if the value being assigned can be represented by the target type.

            int i = 1964;
            uint ui = (uint)i;  // cast works fine

But when casting as part of an unboxing operation, the target type must match the original type exactly.

            int i = 1964;
            object o = i;    // box

            // Attempted unbox to different type
            // Throws InvalidCastException
            uint ui = (uint)o;

This cast, as part of the unboxing operation, is allowed at compile time, but throws an InvalidCastException at run-time.

#219 – Unboxing a Boxed Object

If you’ve converted a value-typed object to a reference-typed object by boxing it, you can later unbox the object, converting it back to a value type.

Assume that we’ve boxed an integer value as follows:

            int i = 1964;
            object o = i;   // Box i

Now we have a copy of the integer in a new object on the heap.

We can later convert this object back to a value type.  This is known as unboxing.

            int j = (int)o;  // Unbox

When we unbox, we need to explicitly cast the object to the value type.  Because the integer derives from System.Object, we can convert it to an object implicitly, but when converting from an object to an int, we need an explicit cast.

As with boxing, unboxing copies the value of the heap-based object.  It does not delete the object on the heap or free its memory.