Object class in C#
In the unified type system of C#, the Object
class an alias for System.Object has a vital role as the ultimate foundation class for all kinds. This implies that all types, whether user-defined or predefined, reference or value types, directly or indirectly derive from System.Object
. Because of this implicit inheritance, all objects in the.NET Framework have a shared base that permits polymorphic behaviour and guarantees that all objects have a set of fundamental functionalities in common.
Explanation of the Object class
This is an explanation of the Object class and what it means:
Root of the Inheritance Hierarchy: In C#, the “root” of the inheritance tree is called an object
. In the absence of explicit inheritance, a class inherently inherits from Object
. All classes you write in C# will therefore either directly or indirectly descend from Object
.
Universal Data Container: Values of any other type can be given to variables of type object
since all types inherit from Object
. The object
type is therefore a universal data container.
- Boxing and Unboxing: It is referred to as boxing when a value type (such as
int
orbool
) is changed to theobject
type. By doing this, anobject
instance is implicitly allocated on the heap, and the value is copied into the newobject
. Unboxing, on the other hand, is the process of getting anobject
type back to a value type.
Core Methods
A number of significant methods defined by the Object
class are inherited by all kinds. To provide more precise or significant implementations, derived classes can frequently override the default behaviours provided by these methods.
ToString()
Method: ToString() is one of the most often used Object
class methods.
Purpose: Its objective is to provide an object’s textual representation.
Default Behavior: The ToString()
method by default derived from System.Object
gives back the type’s complete name, including its namespace. When ToString()
is called on a new object()
instance, for instance, “System.Object” may be printed.
Overriding ToString()
:Classes have the ability to override the ToString()
method to improve the textual representation’s utility and meaning. A derived class can provide its own implementation of a method inherited from its base class by using overriding. As long as the base class method is marked virtual (or is an abstract method), this is accomplished using the override keyword in the derived class. Console.WriteLine()
implicitly invokes the ToString()
function when you feed it an object.
base.ToString()
:In an overridden ToString()
method (or any overridden method), you can use the base keyword to invoke the method’s implementation from the base class. As a result, the functionality can be expanded by the derived class instead of being entirely replaced.
new
Keyword (Method Hiding): It’s critical to distinguish between override and new. A derived class hides the base method if it defines a method using the new keyword but has the same name and signature as a base class method. The base method’s implementation, not the “new” one, will be called in this scenario if the base class type references the object. The most derived implementation is always invoked polymorphically, regardless of the reference type, when override is applied.
Equals()
and GetHashCode()
Methods: Additionally defined by Object are the Equals() and GetHashCode() methods, which can be overridden to supply custom hash code creation and object comparison logic, respectively.
Code Example
Think about a situation where there is a base Animal class and a derived Dog class.
using System;
// Base class: All classes implicitly inherit from System.Object
public class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
// This method is implicitly inherited from System.Object,
// but we can make it virtual to explicitly allow overriding.
// If not marked virtual, a derived class can only 'hide' it with 'new'.
public virtual string MakeSound() // Using 'virtual' to allow polymorphic behavior
{
return "Generic animal sound.";
}
// Overriding ToString() inherited from System.Object
public override string ToString()
{
return $"Animal: {Name}"; // More meaningful representation than default type name
}
}
// Derived class
public class Dog : Animal // Inherits from Animal, which in turn inherits from Object
{
public string Breed { get; set; }
public Dog(string name, string breed) : base(name) // Call base class constructor
{
Breed = breed;
}
// Overriding the virtual MakeSound method from the base class
public override string MakeSound()
{
return "Woof! Woof!";
}
// Further overriding ToString() for Dog, using base's implementation
public override string ToString()
{
return $"{base.ToString()}, Breed: {Breed}"; // Calls Animal's ToString()
}
}
public class ObjectClassExample
{
public static void Main(string[] args)
{
// 1. Instance of the base Object class (though rarely done directly)
object obj = new object(); // All objects in C# inherit from Object
Console.WriteLine($"Default Object.ToString(): {obj.ToString()}");
// Output: System.Object (or similar, depending on namespace/assembly)
Console.WriteLine("--------------------");
// 2. Using our custom Animal class
Animal myAnimal = new Animal("Buddy");
Console.WriteLine($"myAnimal.ToString(): {myAnimal.ToString()}");
// Output: Animal: Buddy (calls overridden ToString in Animal)
Console.WriteLine($"myAnimal.MakeSound(): {myAnimal.MakeSound()}");
// Output: Generic animal sound. (calls virtual MakeSound in Animal)
Console.WriteLine("--------------------");
// 3. Using our custom Dog class
Dog myDog = new Dog("Max", "Golden Retriever");
Console.WriteLine($"myDog.ToString(): {myDog.ToString()}");
// Output: Animal: Max, Breed: Golden Retriever (calls overridden ToString in Dog)
Console.WriteLine($"myDog.MakeSound(): {myDog.MakeSound()}");
// Output: Woof! Woof! (calls overridden MakeSound in Dog)
Console.WriteLine("--------------------");
// 4. Demonstrating Polymorphism with Object and virtual methods
// Reference of base type (Animal) holding an object of derived type (Dog)
Animal polymorphicAnimal = new Dog("Daisy", "Labrador");
Console.WriteLine($"Polymorphic Animal.ToString(): {polymorphicAnimal.ToString()}");
// Output: Animal: Daisy, Breed: Labrador
// At runtime, the correct overridden ToString() from Dog is called
Console.WriteLine($"Polymorphic Animal.MakeSound(): {polymorphicAnimal.MakeSound()}");
// Output: Woof! Woof!
// The overridden method in Dog is executed due to polymorphism
// 5. Explicitly casting to Object to see what happens (though ToString() is overridden)
object dogAsObject = myDog;
Console.WriteLine($"Dog object referenced as System.Object.ToString(): {dogAsObject.ToString()}");
// Output: Animal: Max, Breed: Golden Retriever
// Because ToString() is 'overridden', the derived class's method is called even when referenced as System.Object
// If it were 'new', the Object's ToString() would be called.
}
}
Output
Default Object.ToString(): System.Object
--------------------
myAnimal.ToString(): Animal: Buddy
myAnimal.MakeSound(): Generic animal sound.
--------------------
myDog.ToString(): Animal: Max, Breed: Golden Retriever
myDog.MakeSound(): Woof! Woof!
--------------------
Polymorphic Animal.ToString(): Animal: Daisy, Breed: Labrador
Polymorphic Animal.MakeSound(): Woof! Woof!
Dog object referenced as System.Object.ToString(): Animal: Max, Breed: Golden Retriever
With methods like ToString()
that derived classes can specialise via method overriding to provide polymorphic behaviour, the Object
class acts as the ultimate base, as demonstrated in this example.