In this article, we are going to talk about boxing and unboxing in C#. 

To download the source code for this article, you can visit our GitHub repository.

When we work with C# language constantly, we need to convert data between different data types. For this reason, sometimes we have to use boxing and unboxing when we need to convert a value type to an object type or vice versa.

So, let’s discuss each of these concepts with some examples.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Overview of Value Types and Reference Types

C# is a type-safe programming language containing value types and reference types. Each of them is allocated in different portions of memory: stack and heap.

A value type variable directly contains its data and holds the data within its own memory location. On the other hand, a reference type variable stores a reference to their data (objects). It contains a pointer to another memory location that holds the real data.

In C#, all types inherit from System.Object type, directly or indirectly. This means it’s possible to assign values of any type to object type variables.

NOTE: The object type is an alias to System.Object in .NET, and an object variable is always a reference type.

There are built-in value types in C# like int, bool, double, and char among others, that correspond to the primitive types in .NET. Among built-in reference types, we have string, array, and especially object.

Boxing

Boxing is the process to perform a conversion of a value type to an object type and is an implicit process. 

Let’s see an example of boxing from an int variable to an object:

int valueType = 25;
object objectType = valueType;

Here we declare an int variable named valueType and initialize it with the value of 25. After that, we create an object variable named objectType and assign the int value. As result, the value type variable valueType is copied to the reference type variable objectType:

boxing in c#

Boxing is implicit because we can do it directly:

object objectType = valueType;

Actually, we also can perform the boxing explicitly, but it is never required:

object objectType = (object)valueType;

We also can perform boxing through a method:

public object BoxToInt(int value) => value;

In this method, we have an int parameter and we return it as an object type. 

Unboxing

Unboxing is basically the opposite of boxing. It’s the conversion from an object type to a value type and unlike the boxing process, it is an explicit process.

Let’s consider the same int variable type, that we used in the boxing example, to perform the unboxing:

int valueType = 25; 
object objectType = valueType;     //boxing
int unboxedValue = (int)objectType //unboxing

We declare a new int variable named unboxedValue, and we typecast the objectType variable to an int value:

unboxing in c#

In this case, the conversion must be explicit because the conversion from object to int needs a type casting:

(int)objectType

Otherwise, we’ll have a compiler error CS0266:

Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)

Another important point! We can’t perform an unboxing of a boxed variable to a different type:

int valueType = 25; 
object objectType = valueType;          //boxing
short unboxedValue = (short)objectType; //unboxing

In this case, we get a System.InvalidCastException:

Unable to cast object of type 'System.Int32' to type 'System.Int16'.

Finally, we also can use methods for performing unboxing of different types:

public int UnboxToInt(object o) => (int)o;

So, here we do the reverse process, where we receive the parameter o , which is of object type and as result, we have an int value.

Additional Info About Boxing and Unboxing

When boxing occurs an object reference is created on the stack memory that references a value of the type on the heap memory.

On the other hand, the unboxing copies the value from the instance into a value type variable.

Both are expensive computational processes, so it is highly recommended to use them just when necessary. 

Another care to be taken is that sometimes we could perform, for example, an unboxing without us noticing. It’s the case of the String.Concat method, that is used frequently:

string name = "Joe Doe";
Console.WriteLine(string.Concat(name,"'s age: ", 31));
/* Output:
   Joe Doe's age: 33
*/

Here we concatenate three variables, two of the string type and one of the int type.

But, if we inspect the definition of the Concat method:

public static string Concat(object? arg0, object? arg1, object? arg2) =>
    Concat(arg0?.ToString(), arg1?.ToString(), arg2?.ToString());

We can see it has twelve different overloads, but paying attention to this specific case, which corresponds to what we are using, we’ll see that all parameters are of the object type and there are unboxing processes happening here.

Let’s consider another example using an ArrayList:

var myArrayList = new ArrayList(); 
myArrayList.Add(1);         // int value
myArrayList.Add("Joe Doe"); // string value
myArrayList.Add(1.23);      // double value

foreach (var item in myArrayList) 
   Console.WriteLine(item);

Again, inspecting the definition of the ArrayList.Add method:

public virtual int Add(object? value)

We can notice an unboxing here. 

It will happen the same using a Stack, Queue, or Hashtable:

public virtual void Push(object? obj)              // Stack's method
public virtual void Enqueue(object? obj)           // Queue's method
public virtual void Add(object key, object? value) // Hashtable's method

Conclusion

In this article, we have learned about boxing and unboxing in C#, and how to use both. Also, we’ve mentioned some additional info that we need to consider while working with different C# classes or methods.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!