The Definitive Base Class: The Object Type

The Definitive Base Class: The Object Type

The Object Type

At the top of the hierarchy for all C# types is the object class. Any type in C# can be upcast (implicit conversion) to an object type. This is a very useful thing to know many classes can now use generalised implementations as it is guaranteed that other types will successfully upcast to object.

The base Object type from system
The definitive base class

The implementation of the compiler means that the programmer does not need to declare that they wish to inherit from the object type, instead this inheritance is implicit.

For example, a fixed array of the object type can hold any custom class instances as well as the core C# Types.


                    using System;

public class A
{
    public int a {get; set;} = 1;
	public int b {get; set;} = 2;
	public int c {get; set;} = 3;
}

public class B
{
	public string a {get; set;} = "1";
	public string b {get; set;} = "2";
	public string c {get; set;} = "3";
}

public class Program
{
	public static void Main()
	{
		A a = new A();
		B b = new B();
		string testString = "test";
		double testDouble = 1.234;
		char testChar = 'c';

		object[] data = {a, b, testString, testDouble, testChar};

		foreach(var item in data)
		{
    		Console.WriteLine(item.ToString());
		}
	}
}
                

Boxing and Unboxing

As the Object type is a reference type, the runtime needs to do additional work when converting a value type for use with Object. We call these process boxing and unboxing.

Boxing (Implicit)

Boxing is the process of converting a value type to an object type. Boxing takes the value and allocates an instance of object to wrap it in so it can be moved to the heap. The object type will reference value of the same type that was boxed.

This conversion is implicit as we can be sure that the conversion from value to object will succeed.


                    using System;

public class Program
{
	public static void Main()
	{
		int newValue = 3;
		object o = newValue;
	}
}
                

Unboxing (Explicit)

Unboxing is the opposite of boxing and is, therefore, an explicit conversion. Unboxing takes an instance of an object and converts it back into a value.

It is not guaranteed that this conversion will succeed so first it must be checked that the instance contains a boxed value that is compatible with the target value type. Additionally, although variables of a value type can be null, it is not possible to unbox the null value.


                    using System;

public class Program
{
	public static void Main()
	{
		int testValue = 123;
        object o = testValue;

        try
        {
            int output = (int)o;
            System.Console.WriteLine("Unboxing OK.");
        }
        catch (Exception e)
        {
            System.Console.WriteLine("could not unbox");
        }
	}
}
                

Methods of the Object Type

As every class in C# is derived from the Object class, classes have access to the methods made available by the Object class. A couple of these methods a popular and you may have heard of them before.

If you want to see the full implementation of the type, look here.

GetType

The GetType method will return the runtime type of the instance it was called on.

In the example, we can call GetType on instances of the classes A and B, which will return “A” and “B” respectively.

using System;

public class A
{
}

public class B
{
}

public class Program
{
	public static void Main()
	{
		A a = new A();
		B b = new B();

		Console.WriteLine(a.GetType());
		Console.WriteLine(b.GetType());
	}
}

ToString

ToString is a method that will return the current object as its string representation. By default the ToString function will return the full name of the type of the object, however, this functionality is overridden by many value types such as int.

If ToString is called on an int value type, it will return the value associated with that variable as a string.


                    using System;

public class Program
{
	public static void Main()
	{
		int newValue = 31;
		string valueAsString = newValue.ToString();
		Console.WriteLine(valueAsString);
	}
}
                

When defining a custom class, you might want to override the ToString implementation if you believe it might come in helpful later on.

public override string ToString()
   {
      return base.ToString() + ": " + value.ToString();
   }

Equals

We visited the equals method in an earlier tutorial, its purpose is to compare the current object with a target object, the method will return true if this is the case and false if not. This is different than comparing the objects references.