Article

System.Object.Equals() virtual method

The Equals() is a virtual method defined in the System.Object class. Since every class is implicitly derived from Object, it provides the Equals() method.

public virtual bool Equals(object obj)

By default, it compares the two object references at run time. It determines if an invoking object refers to the same object as the one referred to by obj. It returns true if they refer to the same instance. This is the default implementation for Equals in System.Object.

You can override this method in your classes. For instance, you may want Equals() to test for equal values rather than equal references i.e. compare the contents of two objects for equality. The default implementation provided by System.Object won't be adequate in this case, therefore you must override Equals and provide your own implementation. Notice that if a class doesn't explicitly override Equals, it inherits the implementation (overridden Equals) provided by the nearest base class while moving up the hierarchy.

When you implementing Equals method for your class, make sure that the following rules are observed.

a. Symmetric: a.Equals(a) must return true

b. Reflexive: a.Equals(b) must return the same value as b.Equals(a)

c. Transitive: if a.Equals(b) returns true and b.Equals(c) return true then a.Equals(c) must also return true

d. Consistent: a.Equals(b) must continue to return the same value if the objects referenced by a and b are not modified

e. a.Equals(null) must return false

f. Don't throw exceptions in Equals

g. If you want to override Equals, you must override GetHashCode() method. The compiler gives a warning if you override just one of them, discussed later.

There is no guarantee that your app will work properly if these rules are not followed. Its implementation is not as simple as you might anticipate.

Equals() method for value types

All value types are derived from the System.ValueType class. The ValueType provides a default implementation of Equals() for value types. It overrides the implementation provided by System.Object. It returns true if the two types are identical and the fields of both the types have the same value.

All value types inherit the implementation provided by ValueType. However, for instance, if you want to improve performance with a custom implementation that runs considerably faster, you can explicitly override the Equals() and provide your own implementation for the value types you define.

struct MyStruct {
    ...
    public override Boolean Equals(Object obj) { }
}

System.Object.Equals() static method

public static bool Equals(Object obj1, Object obj2)

It is an overloaded form of Equals() that is declared as static. This means that this form of Equals() method should not be accessed through some class instance. This is in contrast to Equals(obj) form which can be accessed only through a class instance.

It is implemented as follows: a. First it checks to see whether obj1 or obj2 is null. The method returns false if either obj1 or obj2 is null.

b. If not null, it calls obj1.Equals(obj2) and returns the result

Note that in this form of Equals() i.e. Equals(obj1, obj2), it is legal for obj1 and obj2 to have a value of null. However in the other form i.e. obj1.Equals(obj2), if obj1 is null, obj1.Equals(obj2) will throw an exception.

Overloading the == operator

By default, it compares the object references for reference types. If you want to compare the actual contents of an object, you can overload this operator in your class to get the desired behavior.

For instance, the String class overloads the == operator. When the two string references are the operands, the values of the strings are compared for equality. Note that String.Equals() method can also be used to compare the contents of the strings for equality.

The rule of thumb is whenever you overload the == operator, override the Equals() method. You should ask them to do the same work.

Example

class Student {
    int id;
    public class Student (int id) { this.id =id; }

    //Perform all operations that are required to compare the states of two objects
    public override bool Equals(Object obj) {

        //If both the references point to the same object, they must be equal
        if (this == obj)
            return true;

        //The objects cannot be equal if obj is null
        if (obj == null)
            return false;

        //The objects cannot be equal if they are of different types
        if (this.GetType() != obj.GetType())
            return false;

        //Now you can cast obj to the Student type. Notice this casting operation will 
        //not throw an exception because the objects are of the same type.
        Student other = (Student) obj;

        //Compare the two value type fields. Call the field type's (in our case int) 
        //Equals method. Note that this Equals() is a compiler provided implementation 
        //for int type.
        if (!id.Equals(other.id))
            return false;

        //Note: Alternatively, two value type fields can be compared in the following 
        //manner. This statement is equivalent to the statement written above:
        //if (!(id == other.id)) return false;
        //Here the compiler-provided implementation of == operator in int value type 
        //will be used

        //return true returned if all the fields are equal
        return true;
    }

    //Overload the == operator. In general, == and Equals should perform the same action
    public static Boolean operator== (Student obj1, Student obj2) {
        if (obj1 == null)
            return false;

        //Invoke the Equals() version implemented above
        return obj1.Equals(obj2);
    }

    //The == and != should be overloaded in pair
    public static Boolean operator!= (Student obj1, Student obj2) {
        return !(obj1 == obj2);
    }

    //GetHashCode is discussed later
    public override int GetHashCode() {
        return id ;
    }
}

//User of the Student class
Student a = new Student(1);
Student b = new Student(2);
Student c = new Student(2);
a.Equals(c);        //returns false
b.Equals(c);        //returns true

For Part 2, click this link: Overriding the Equals() and GetHashCode() methods in C# - Part 2