C# Object Type Tutorial

In this tutorial we learn more about the base class for all data types in C#, the object type. We cover how to declare an object type and object arrays.

We also cover Boxing and Unboxing, how it works and the impact it has.

What is the object type

The object type is an alias for the System.Object class which is the base class for all data types in the C# CTS (Common Type System).

We can assign values of any type to a variable that is of type object:

  • Value types
  • Reference types
  • Predefined types
  • User-defined types

How to declare an object type

To declare or initialize a variable of object type, we use the keyword object as the type.

Syntax:
// declaration
object variable_name;

// initialization
object variable_name = some_value;
Example:
using System;

namespace ObjectType
{
    class Program
    {
        static void Main()
        {
            object number;
            object message = "Hello World";

            Console.WriteLine(message);
            Console.ReadLine();
        }
    }
}

Object arrays

Object arrays can store elements of different types in a single collection, almost like a Tuple.

Example:
using System;

namespace ObjectType
{
    class Program
    {
        static void Main()
        {
            object[] crazyArr = new object[3] { 1, 3.14, "Hello World" };

            foreach(object e in crazyArr)
            {
                Console.WriteLine("Type: {0} Value: {1}", e.GetType(), e.ToString());
            }

            Console.ReadLine();
        }
    }
}

Object arrays not only make our code more complex, it also decreases performance at runtime. If possible, we should try to avoid object arrays.

Boxing and unboxing object types

Before a value type is assigned to an object type, it needs conversion.

Example:
namespace ObjectType
{
    class Program
    {
        static void Main()
        {
            // boxing
            object num = 10;
        }
    }
}

In the example above we are copying the value of num to a new reference on the heap. So even though the integer 10 is a value type, num is now a reference type that refers to the object on the heap. This is called boxing.

When we need to get the value back out of the boxed object, we are unboxing it. We can only unbox the value from the object that was stored as its exact type, which we do with casting syntax.

Example:
namespace ObjectType
{
    class Program
    {
        static void Main()
        {
            // boxing
            object num = 10;

            // unboxing
            int number = (int)num;
        }
    }
}

The object is of type integer so it needs to be unboxed back into an integer. We use casting syntax with the type between parentheses in front of the object we want to unbox.

What is the difference between boxing and type casting

Many new C# developers are often confused about the difference between boxing / unboxing and type casting. We’ll try to explain the differences here.

Short (basic) Version

  • Casting will change a value type on the stack into another value type on the stack.
  • Boxing will copy the value of the value type from the stack into a new reference on the heap.
  • Unboxing is getting the value back from the boxed object and can only be unboxed as the value’s exact type.

The difference is that with boxing and unboxing, additional memory is allocated as each new reference is created. That’s also why constant boxing and unboxing is expensive on system resources.

Longer (basic) Version

As we saw in the Stack vs. Heap tutorial , value types are stored on the stack and reference types on the heap.

Boxing is where we copy the value of a value type to an object reference on the heap, unboxing is reading the value from the object. We can only unbox the value as its exact type.

Example:
// boxing
object num = 10;

// unboxing
int number = (int)num;

While we use casting syntax in the unboxing, casting and unboxing are two different operations.

Casting is when we convert one basic type, to another basic type.

Example:
// implicit casting
byte b = 25;
int i = b;

// explicit casting
int i = 300;
byte b = (byte)i;

Or changing the type of a reference.

Example:
List<Movies> MovieList;

IEnumerable MoviesIE = (IEnumerable)MovieList;

Both byte and int are values types before, and after, the cast.

Summary: Points to remember

  • An object type is the base for all data types in C#
    • All types of values can be assigned to an object type. Value, reference, predefined and user-defined types.
  • Object arrays can store different types of data in a collection, similar to a tuple.
  • When a value type is assigned to an object type, it gets converted beforehand. This is called boxing.
    • When we retrieve the boxed object, it must be unboxed first. Unboxing may be heavy on system resources.