Introduction
In this article I will explain the concepts of Boxing and UnBoxing. C# provides us with Value types and Reference Types. Value Types are stored on the stack and Reference types are stored on the heap. The conversion of value type to reference type is known as boxing and converting reference type back to the value type is known as unboxing.
Let me explain you little more about Value and Reference Types.
Value Types
Value types are primitive types that are mapped directly to the FCL. Like Int32
maps to System.Int32
, double
maps to System.double
. All value types are stored on stack and all the value types are derived from System.ValueType
. All structures and enumerated types that are derived from System.ValueType
are created on stack, hence known as ValueType
.
Reference Types
Reference Types are different from value types in such a way that memory is allocated to them from the heap. All the classes are of reference type. C# new
operator returns the memory address of the object.
Examples
Lets see some examples to have a better understanding of Value Types and Reference Types. Since we know that all ValueTypes are derived from System.Value
we can write something like this:
System.ValueType r = <SPAN class=cs-literal nd="14">5;
So what do you think about the above line of code. Will it compile ? Yes it will compile. But wait what type is it cause I don't remember any type which is called System.ValueType
since its a base class from which all value types inherit. So is it Int32
, Int64
,double
, decimal
etc. It turns out that the type for variable 'r' is System.Int32
. The Question arrises why Int32
and why not Int16
. Well its because it is mapped to Int32
by default depending upon the Initial value of the variable.
You cannot write something like this since System.ValueType
is not a primitive type its a base class for primitive value types and these mathematical operations can be performed on primitive types.
System.ValueType r = <SPAN class=cs-literal nd="27">10;
r++;
In the above example I told you that variable 'r' will be a System.Int32
variable but if you don't believe me than you can find out yourself using the GetType()
method:
System.ValueType r = <SPAN class=cs-literal nd="32">5;
Console.WriteLine(r.GetType()) <SPAN class=cs-comment nd="33">
Here are few samples you can try on your own:
Collapse
System.ValueType r = <SPAN class=cs-literal nd="37">23.45;
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="38">
<SPAN class=cs-comment nd="39">
System.ValueType r = <SPAN class=cs-literal nd="40">23.45F;
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="41">
<SPAN class=cs-comment nd="42">
System.ValueType r = 2U;
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="43">
<SPAN class=cs-comment nd="44">
System.ValueType r = 'c';
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="45">
<SPAN class=cs-comment nd="46">
System.ValueType r = 'ac';
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="47">
<SPAN class=cs-comment nd="48">
System.ValueType r = <SPAN class=cpp-string nd="49">"Hello World";
Console.WriteLine(r.GetType()); <SPAN class=cs-comment nd="50">
Lets now jump to Boxing. Sometimes we need to convert ValueTypes to Reference Types also known as boxing. Lets see a small example below. You see in the example I wrote "implicit boxing" which means you don't need to tell the compiler that you are boxing Int32
to object because it takes care of this itself although you can always make explicit boxing as seen below right after implicit boxing.
Int32 x = <SPAN class=cs-literal nd="54">10;
<SPAN class=cs-keyword nd="55">object o = x ; <SPAN class=cs-comment nd="56">
Console.WriteLine(<SPAN class=cpp-string nd="57">"The Object o = {0}",o); <SPAN class=cs-comment nd="58">
<SPAN class=cs-comment nd="59">
Int32 x = <SPAN class=cs-literal nd="60">10;
<SPAN class=cs-keyword nd="61">object o = (<SPAN class=cs-keyword nd="62">object) x; <SPAN class=cs-comment nd="63">
Console.WriteLine(<SPAN class=cpp-string nd="64">"The object o = {0}",o); <SPAN class=cs-comment nd="65">
Lets now see UnBoxing an object type back to value type. Here is a simple code that unbox an object back to Int32
variable. First we need to box it so that we can unbox.
Int32 x = <SPAN class=cs-literal nd="69">5;
<SPAN class=cs-keyword nd="70">object o = x; <SPAN class=cs-comment nd="71">
x = o; <SPAN class=cs-comment nd="72">
So, you see how easy it is to box and how easy it is to unbox. The above example first boxs Int32
variable to an object type and than simply unbox it to x
again. All the conversions are taking place implicitly. Everything seems right in this example there is just one small problem which is that the above code is will not compile. You cannot Implicitly convert a reference type to a value type. You must explicity specify that you are unboxing as shown in the code below.
Int32 x = <SPAN class=cs-literal nd="77">5;
<SPAN class=cs-keyword nd="78">object o = x; <SPAN class=cs-comment nd="79">
x = (Int32)o; <SPAN class=cs-comment nd="80">
Lets see another small example of unboxing.
Int32 x = <SPAN class=cs-literal nd="83">5; <SPAN class=cs-comment nd="84">
Int64 y = <SPAN class=cs-literal nd="85">0; <SPAN class=cs-comment nd="86">
<SPAN class=cs-keyword nd="87">object o = x; <SPAN class=cs-comment nd="88">
y = (Int64)o; <SPAN class=cs-comment nd="89">
Console.WriteLine(<SPAN class=cpp-string nd="90">"y={0}",y);
This example will not work. It will compile successfully but at runtime It will generate an exception of System.InvalidCastException
. The reason is variable x is boxed as Int32
variable so it must be unboxed to Int32
variable. So, the type the variable uses to box will remain the same when unboxing the same variable. Of course you can cast it to Int64 after unboxing it as Int32
as follows:
Int32 x = <SPAN class=cs-literal nd="97">5; <SPAN class=cs-comment nd="98">
Int64 y = <SPAN class=cs-literal nd="99">0; <SPAN class=cs-comment nd="100">
<SPAN class=cs-keyword nd="101">object o = x; <SPAN class=cs-comment nd="102">
y = (Int64)(Int32)o; <SPAN class=cs-comment nd="103">
Console.WriteLine(<SPAN class=cpp-string nd="104">"y={0}",y);