Overriding the System.Object class methods

In this article you will take a look on the Object class the base class for all data types in the .NET Framework. You will see also how to give your custom type a new look by overriding the Object class virtual methods.


Introduction:

 

Let us start by creating a new class and we will leave it with out any methods.

 

public class Employee

{

} 

In the next step we will try to use our class, we will find that our Employee class contains 4 methods which are (Equals, GetHashCode, GetType, and ToString).

 

 

 

 

The question now, from where these four methods come from?

 

The answer is easy: any data type in the .Net inherits implicitly from the Object class which defines a common set of members supported by every type in the .NET, so when we create our new class Employee it inherits from the Object class.

 

The Object base class defines some members that are virtual so it allows us to redefine the default implementation of these members.

 

These virtual members give you a good work, but in some cases you will need a new implementation of these methods to fit your class functionality.

 

In the next section we will see how to use the default implementation of the Object class virtual methods and then we will try to redefine it by using override keyword to give it a new behavior.

 

ToString() Method:

 

The ToString() method gives you a textual representation of the current state of the object.

 

Example:

 

namespace UsingObjectClass

{

    public class Employee

    {

        string firstName;

        public string FirstName

        {

            get { return firstName; }

            set { firstName = value; }

        }

 

        string lastName;

        public string LastName

        {

            get { return lastName; }

            set { lastName = value; }

        }

 

        int age;

        public int Age

        {

            get { return age; }

            set { age = value; }

        }

 

        string employeeID;

        public string EmployeeID

        {

            get { return employeeID; }

            set { employeeID = value; }

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Employee emp1 = new Employee();

            emp1.FirstName = "Amr";

            emp1.LastName = "Ashush";

            emp1.Age = 23;

 

            string s = emp1.ToString();

            Console.WriteLine(s);

        }

    }

}

 

The result:

 

 

As you can see the returned string is the name of the Employee Type (UsingObjectClass.Employee).

 

What if we want to use the ToString() method to show the current employee data (First Name, Last Name, and Age).

 

All we need to do is to override the ToString() Method to give it a new behavior, so in our case we will redefine it to show the Employee data instead of the name of the object type.

 

Overriding ToString() Method:

 

The first step is to use the override keyword to override the method and then we will redefine its behavior.

 

Example: 

 

public class Employee

{

....

    //Overriding ToString() method

    public override string ToString()

    {

        string s = "First Name: " + firstName + " , " + " last Name: " + lastName + " , " +"and Age: " + age;

        return s;

    }

}

 

Trying the new behavior of the ToString() method: 

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

 

string s = emp1.ToString();

Console.WriteLine(s);

 

The result:

 

 

As you can see we now have a good text representation of our object.

 

We can use also StringBuilder in our ToString() method as follow:

 

public override string ToString()

{

    StringBuilder sb = new StringBuilder();

    sb.AppendFormat("First Name: {0}, Last Name: {1}, and Age: {2}", firstName, lastName, age);

    return sb.ToString();

}

 

Equals() Method:

 

Equals() method is used to compare two objects and it returns a true if these objects point to the same values on the heap and returns false if not.

 

Example:

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

 

Employee emp2 = emp1;

 

We now have two objects that point to the same value on the heap, so if we tried to use Equals() method it will return true.

 

//this will return True.

emp1.Equals(emp2);

Now we will create two objects each one has its own value on the heap, so when we use Equals() method it will return False.

 

Employee emp3 = new Employee();

emp3.FirstName = "Amr";

emp3.LastName = "Ashush";

emp3.Age = 40;

emp3.EmployeeID = "123A";

 

Employee emp4 = new Employee();

emp4.FirstName = "Amr";

emp4.LastName = "Ashush";

emp4.Age = 23;

emp4.EmployeeID = "123A";

 

//this will return False.

emp3.Equals(emp4);

 

Overriding Equals() Method:

 

Consider that we want to compare two objects but we do not want to know if these objects pointing to the same value in the heap, all we need to know that if these two objects have the same data like (First Name, and Last Name) for example.

 

Example:

 

//Overriding Equals() method

public override bool Equals(object obj)

{

    if (obj != null && obj is Employee)

    {

        Employee emp = (Employee)obj;

        if (emp.firstName == this.firstName &&

            emp.lastName == this.lastName &&

            emp.employeeID == this.employeeID)

            return true;

    }

    return false;

}

 

Now when we try to use the Equals() method it will compare the firstName, lastName, and employeeID of the two objects and it will return true if these value are the same and false if not.

 

Example:

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

emp1.EmployeeID = "123A";

 

Employee emp2 = new Employee();

emp2.FirstName = "Amr";

emp2.LastName = "Ashush";

emp2.Age = 23;

emp2.EmployeeID = "123A";

 

//this will return True.

emp1.Equals(emp2);

 

If we have two objects with different data Equals method will return false.

 

Employee emp3 = new Employee();

emp3.FirstName = "Jack";

emp3.LastName = "Baher";

emp3.Age = 40;

emp3.EmployeeID = "1254B";

 

Employee emp4 = new Employee();

emp4.FirstName = "James";

emp4.LastName = "Bond";

emp4.Age = 23;

emp4.EmployeeID = "007";

 

//this will return False.

emp3.Equals(emp4);

 

GetHashCode() Method:

 

The GetHashCode() method is used to return a numerical value that identefies an object based on its internal data.

 

Example:

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

emp1.EmployeeID = "125";

 

Employee emp2 = new Employee();

emp2.FirstName = "Amr";

emp2.LastName = "Ashush";

emp2.Age = 23;

emp2.EmployeeID = "125";

           

Console.WriteLine("emp 1 hash code: {0}", emp1.GetHashCode());

Console.WriteLine("emp 2 hash code: {0}", emp2.GetHashCode());

 

the result will be:

 

emp 1 hash code: 45653674

emp 2 hash code: 41149443

 

As you can see, instead of the two objects have the same data, each one have different hash code because each object points to a different place on the heap.

 

So if we create two objects that point to the same value, when we call GetHashCode() method from any one we will get the same hash code.

 

Example:

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

emp1.EmployeeID = "125";

 

Employee emp2 = emp1;

 

Console.WriteLine("emp 1 hash code: {0}", emp1.GetHashCode());

Console.WriteLine("emp 2 hash code: {0}", emp2.GetHashCode());

 

the result will be:

 

emp 1 hash code: 45653674

emp 2 hash code: 45653674

 

 

Overriding GetHashCode() Method:

 

We need to override GetHashCode() method so if we have two objects with identical data we will obtain the same hash code.

 

The String class has its own implementation of GetHashCode() method based on the string's character data.

 

We can use the string that return from the overriden ToString() method and use it to call GetHashCode() method. So if we have two objects with the same First Name, Last Name, and Age we will obtain the same hash code.

 

//Overriding the GetHashCode method

public override int GetHashCode()

{

    return ToString().GetHashCode();

}

 

Example:

 

Employee emp1 = new Employee();

emp1.FirstName = "Amr";

emp1.LastName = "Ashush";

emp1.Age = 23;

emp1.EmployeeID = "125";

 

Employee emp2 = new Employee();

emp2.FirstName = "Amr";

emp2.LastName = "Ashush";

emp2.Age = 23;

emp2.EmployeeID = "125";

           

Console.WriteLine("emp 1 hash code: {0}", emp1.GetHashCode());

Console.WriteLine("emp 2 hash code: {0}", emp2.GetHashCode());

 

the result will be:(the same hash code)

 

emp 1 hash code: -1503318716

emp 2 hash code: -1503318716

 

As you can see we get the same hash code although we have two object that are point to different values on the heap.

 

Another option is to identify a string field that should be unique among objects and then return its hash code.

In our case EmployeeID suould be unique so if we have two object with the same EmployeeID we will get the same hash code.

 

//Overriding the GetHashCode method

public override int GetHashCode()

{

    return EmployeeID.GetHashCode();

}

 

Note: Overriding GetHashCode() method only useful when you want to store your object in hash-based collection such as Hashtable beacause the Hashtable type calles the Equals() and GetHashCode() methods of the contained objects under the hood to determine the correct object to return to the caller. and the Object class has no idea about the data on its subclasses.

 

Note: If you override Equals() method and do not override GetHashCode() method you will get a compiler warning. 

 

We are done for now.

 

Thank you for reading, see you next article.