The Object Class in .NET using C#

Introduction

 
In my opinion, learning the C# language is fascinating. I hope you agree, especially to those who have been using it for a while in their career. I still remember back when I was starting out, I noticed that when I typed anything within Visual Studio, it seems that everything behaves like an object. To elaborate further, for example when you have typed a literal number and magically you can invoke the ToString() method after you have typed dot (.).
 
In this blog post, we are going to discuss the System.Object class. Thus, in this post we are going to tackle the following topics:
  • What is the System.Object class?
  • Summarized purposes of the object class methods

What is the System.Object class?

All .NET classes are ultimately derived from the System.Object class. In fact, when you don’t specify a base class while defining a class, the compiler automatically assumes that it derives from System.Object. Lastly, because of this behavior, you have access to many public, protected member methods that have been defined for the Object class.
 
To prove some of the statements above, I have created a unit test to prove the following:
  • System.Object is the parent of all classes within the .NET.
  • All class builtin and/or defined is a subclass of System.Object
See the sample code below:
  1. [Fact]  
  2. public void UnitTest_Get_Base_Class_Of_DotNet_Classes()  
  3. {  
  4.     //get the assembly name of .net core  
  5.     string assemblyFullName = "System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e";  
  6.   
  7.     //load the assembly  
  8.     Assembly assembly = Assembly.Load(assemblyFullName);  
  9.   
  10.     //filter base on the following criteria  
  11.     // Doesn't have a base type because System.Object is the root of all types within the .NET Core  
  12.     // System.Object is a class and ansiclass  
  13.     TypeInfo baseOfAllClasses = assembly.DefinedTypes.FirstOrDefault(x => x.BaseType == null && x.IsClass && x.IsAnsiClass);  
  14.   
  15.     string objectAlias = string.Empty;  
  16.   
  17.     using (var provider = new CSharpCodeProvider())  
  18.     {  
  19.         objectAlias = provider.GetTypeOutput(new CodeTypeReference(baseOfAllClasses));  
  20.     }  
  21.   
  22.     Assert.True(objectAlias == "object");  
  23.   
  24. }  
Above, as you can see, we have loaded the assembly System.Private.CoreLib of .NET Core and filtered into a type that has no base type, a class, and an ANSI class. As a result, we've got back the System.Object or object as the result. 
  1. [Fact]  
  2. public void UnitTest_Check_Base_Class_Of_System_Object()  
  3. {  
  4.     object obj = new object(); //create new instance of object  
  5.   
  6.     Assert.IsType<object>(obj); //check if object  
  7.   
  8.     Type objType = obj.GetType();  
  9.   
  10.     Assert.Null(objType.BaseType); //doesn't have a base type  
  11.   
  12.     Assert.True(objType.Name == "Object");  
  13.     Assert.True(objType.FullName == "System.Object");  
  14.     Assert.True(objType.Namespace == "System");  
  15.   
  16.     Assert.True(objType.IsAnsiClass);//is ansiclass  
  17.     Assert.True(objType.IsClass);//is class  
  18.   
  19. }  
Above, we have created a new instance of System.Object and checked some properties to see if they're valid. 
  1. [Fact]  
  2. public void Prove_That_All_Classes_Reference_And_Value_Types_Are_Derived_From_System_Object()  
  3. {  
  4.     Assert.True(typeof(string).IsSubclassOf(typeof(object)));  
  5.   
  6.     Assert.True(typeof(Array).IsSubclassOf(typeof(object)));  
  7.   
  8.     // this is the main reason why value types and primitive types behaves like an object  
  9.     Assert.True(typeof(ValueType).IsSubclassOf(typeof(object)));  
  10. }  
Above, we have just proved that everything is derived from the System.Object class.

Summarized purposes of the object class methods

Before dealing with the different properties and methods that we can directly inherit from the Object class, first let's try to answer this question: Why are all types in .NET derived from the object/System.Object class? 
  • It gives the developer a universal behavior of the properties and methods of the object class. Therefore; it can be used in any type of the .NET core/framework. 
  • Developers have the ability to pass anything generically as an object. 
  • Developers can refer to objects of unknowable type, especially when using reflection. 
I might not be able to give a lot of answers to this design decision. However; the list above was base on my experience and observation with the .NET core/framework since day one. 

GetHashCode 

If you intend your class to be used as a key for a dictionary, you need to override GetHashCode. Basically, this method returns a hashcode for an object. 

ToString 

This is fairly easy, it just helps the developer to have a quick-and-easy string representation of the type used. See an example usage below.
  1. [Fact]  
  2. public void UnitTest_ToString()  
  3. {  
  4.     Assert.True("5" == 5.ToString());  
  5.     Assert.True((89.99m).ToString() == "89.99");  
  6.     Assert.True(true.ToString() == "True");  
  7.     Assert.True(true.ToString() == bool.TrueString);  
  8.     Assert.True(false.ToString() == "False");  
  9.     Assert.True(false.ToString() == bool.FalseString);  
  10. }  

Equals and ReferenceEquals

Using these two Equals and ReferenceEquals gives you the ability to compare objects. See an example usage below.
  1. [Fact]  
  2. public void UnitTest_Object_Equals_Static_And_Virtual()  
  3. {  
  4.   
  5.     Assert.True(5.Equals(5));  
  6.   
  7.     object first = null;  
  8.     object second = null;  
  9.   
  10.     Assert.True(object.ReferenceEquals(first, second));  
  11.   
  12.     first = new object();  
  13.   
  14.     Assert.False(object.ReferenceEquals(first, second));  
  15.   
  16.     second = first;  
  17.   
  18.     Assert.True(object.ReferenceEquals(first, second));  
  19. }  

GetType

This method gives you the ability to get the type of the object. See an example of usage below. 
  1. [Fact]  
  2. public void Unit_Test_Object_GetType()  
  3. {  
  4.     int num = 5;  
  5.     decimal num2 = 5.23m;  
  6.     string name = "jin";  
  7.   
  8.     Assert.True(num.GetType() == typeof(int));  
  9.     Assert.True(num2.GetType() == typeof(decimal));  
  10.     Assert.True(name.GetType() == typeof(string));  
  11.       
  12. }  

Summary

 
In this blog post, we have discussed the System.Object class and gave a reasonable list of why this was beneficial. I hope you have enjoyed this blog post, as I have enjoyed writing it. You can also find the sample code here at GitHub. Until next time, Happy programming!