A boxing conversion permits any value-type to be implicitly converted to the type object
or to any interface-type implemented by the value-type. Boxing a value of a value-type consists of allocating an object instance and copying the value-type value into that instance.
The actual process of boxing a value of a value-type is best explained by imagining the existence of a boxing class for that type. For any value-type T
, the boxing class would be declared as follows:
class T_Box { T value; T_Box(T t) { value = t; } }
Boxing of a value v
of type T
now consists of executing the expression new T_Box(v)
, and returning the resulting instance as a value of type object
. Thus, the statements
int i = 123; object box = i;
conceptually correspond to
int i = 123; object box = new int_Box(i);
Boxing classes like T_Box
and int_Box
above don’t actually exist and the dynamic type of a boxed value isn’t actually a class type. Instead, a boxed value of type T
has the dynamic type T
, and a dynamic type check using the is
operator can simply reference type T
. For example,
int i = 123; object box = i; if (box is int) { Console.Write("Box contains an int"); }
will output the string "Box contains an int
" on the console.
A boxing conversion implies making a copy of the value being boxed. This is different from a conversion of a reference-type to type object
, in which the value continues to reference the same instance and simply is regarded as the less derived type object
. For example, given the declaration
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } }
the following statements
Point p = new Point(10, 10); object box = p; p.x = 20; Console.Write(((Point)box).x);
will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p
to box
causes the value of p
to be copied. Had Point
instead been declared a class
, the value 20 would be output because p
and box
would reference the same instance.