Microsoft TechNet
37 out of 51 rated this helpful - Rate this topic

Guidelines for Overloading Equals() and Operator == (C# Programming Guide)

Visual Studio 2005

In C#, there are two different kinds of equality: reference equality and value equality. Value equality is the commonly understood meaning of equality: it means that two objects contain the same values. For example, two integers with the value of 2 have value equality. Reference equality means that there are not two objects to compare. Instead, there are two object references, both of which refer to the same object. This can occur through simple assignment, as shown in the following example:

System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b);  //returns true

In this code, only one object exists, but there are multiple references to that object: a and b. Because they both refer to the same object, they have reference equality. If two objects have reference equality, then they also have value equality, but value equality does not guarantee reference equality.

To check for reference equality, use ReferenceEquals. To check for value equality, use Equals or Equals.

Equals is a virtual method, enabling any class to override its implementation. Any class that represents a value, essentially any value type, or a set of values as a group, such as a complex number class, should override Equals. If the type implements IComparable, it should override Equals.

The new implementation of Equals should follow all the guarantees of Equals:

  • x.Equals(x) returns true.

  • x.Equals(y) returns the same value as y.Equals(x).

  • if (x.Equals(y) && y.Equals(z)) returns true, then x.Equals(z) returns true.

  • Successive invocations of x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.

  • x.Equals(null) returns false.

The new implementation of Equals should not throw exceptions. It is recommended that any class that overrides Equals also override System.Object.GetHashCode. It is also recommended that in addition to implementing Equals(object), any class also implement Equals(type) for their own type, to enhance performance. For example:

class TwoDPoint : System.Object
{
    public readonly int x, y;

    public TwoDPoint(int x, int y)  //constructor
    {
        this.x = x;
        this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        TwoDPoint p = obj as TwoDPoint;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

Any derived class that can call Equals on the base class should do so before finishing its comparison. In the following example, Equals calls the base class Equals, which checks for a null parameter and compares the type of the parameter with the type of the derived class. That leaves the implementation of Equals on the derived class the task of checking the new data field declared on the derived class:

class ThreeDPoint : TwoDPoint
{
    public readonly int z;

    public ThreeDPoint(int x, int y, int z)
        : base(x, y)
    {
        this.z = z;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter cannot be cast to ThreeDPoint return false:
        ThreeDPoint p = obj as ThreeDPoint;
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return base.Equals(obj) && z == p.z;
    }

    public bool Equals(ThreeDPoint p)
    {
        // Return true if the fields match:
        return base.Equals((TwoDPoint)p) && z == p.z;
    }

    public override int GetHashCode()
    {
        return base.GetHashCode() ^ z;
    }
}

By default, the operator == tests for reference equality by determining if two references indicate the same object, so reference types do not need to implement operator == in order to gain this functionality. When a type is immutable, meaning the data contained in the instance cannot be changed, overloading operator == to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. Overriding operator == in non-immutable types is not recommended.

Overloaded operator == implementations should not throw exceptions. Any type that overloads operator == should also overload operator !=. For example:

//add this code to class ThreeDPoint as defined previously
//
public static bool operator ==(ThreeDPoint a, ThreeDPoint b)
{
    // If both are null, or both are same instance, return true.
    if (System.Object.ReferenceEquals(a, b))
    {
        return true;
    }

    // If one is null, but not both, return false.
    if (((object)a == null) || ((object)b == null))
    {
        return false;
    }

    // Return true if the fields match:
    return a.x == b.x && a.y == b.y && a.z == b.z;
}

public static bool operator !=(ThreeDPoint a, ThreeDPoint b)
{
    return !(a == b);
}

NoteNote

A common error in overloads of operator == is to use (a == b), (a == null), or (b == null) to check for reference equality. This instead results in a call to the overloaded operator ==, causing an infinite loop. Use ReferenceEquals or cast the type to Object, to avoid the loop.

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Example breaks transitivity

Transitivity: if x.Equals(y) and y.Equals(z) then x.Equals(z)

object y = new ThreeDPoint(1, 2, 3);object y = new ThreeDPoint(1, 2, 3);
object x = new ThreeDPoint(1, 2, 3);
object y = new TwoDPoint(1, 2);
object z = new ThreeDPoint(1, 2, 4);

y.Equals(x); //true
y.Equals(z); //true
x.Equals(z); //false - transitivity broken

It is not possible to follow all of the equlity rules when inheriting, so TwoDPoint should be sealed to prevent it. And both classes could implement ITwoDPoint if needed.
Why must one overload that much?
The c++ STL requires only equality and "smaller than".
So, theoretically, overloading == and < ought to suffice, with all the other operators having default implementations relying on these two.
Incorrect condition

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))

Should be
if ( ( ((object)a == null) || ((object)b == null) ) && ((object)a != null) || ((object)b != null) )

CS Team: Notice that the if statement right before this one already picks off the equal cases, and returns. So at this point in the code, they cannot both be null.

No it should use the XOR operator!



Clarification Required
What is the difference between Equals(Object) and Equals(Object, Object) with respect to internal implementation.
Example code is correct

object x = new TwoDPoint(1, 2);
object y = new ThreeDPoint(1, 2, 3);
y.Equals(x); // Returns false
x.Equals(y); // Returns true(!)


As quoted in the article 'x.Equals(y) returns the same value as y.Equals(x). But here y.Equals(x) and x.Equals(y) are not returning the same value. But this is not a bug, actually this statement holds true when both x,y are of same type.

If object x and y would have been of same type then the outcome of those two method calls is same. Point to be noted

Example code is correct

Well, nobody seems to have gone there so I will. The following code...

object x = new TwoDPoint(1, 2);
object y = new ThreeDPoint(1, 2, 3);
y.Equals(x); // Returns false
x.Equals(y); // Returns true(!)


Is actually correct. ThreeDPoint derives from TwoDPoint, so when the call x.Equals(y) is made, the method used will be the one defined in TwoDPoint (bool Equals(TwoDPoint p) presumbably). The supplied 'y' parameter is cast to a TwoDPoint, the internal 'x' and 'y' fields are compared, found to be equal and so true is returned.

The default operator == should call Equals not ReferenceEquals

The default object == operator should really call Equals instead of ReferenceEquals. This would allow polymorphic use of the == operator and greatly improve things for interface based programming. Since the defalt Equals method simply calls ReferenceEquals this wouldn't incur any additional overhead. I view this as a giant oversight in the language.

^ is a poor method of combining hashcodes
To combine hashCode1 and hashCode2

int nullHashCode = 0x61E04917; //sufficiently large random number
finalHashCode = nullHashCode;
finalHashCode = (finalHashCode << 5) + hashCode1
finalHashCode = (finalHashCode << 5) + hashCode2

See http://musingmarc.blogspot.com/2007/08/vtos-rtos-and-gethashcode-oh-my.html for the gory details
Condition is correct

The earlier call to ReferenceEquals will handle both being null and the specific code won't be reached. Therefore you only have to test for one or the other being null as being a condition for inequality.

If you want to write less confusing code, don't forget the exclusive-or operator: ^ . It will work with both logical and binary operations. It is great for looking for mismatching conditions:

if ((object)a == null ^ (object)b == null)
{
return false;
}

(Also note that with C# you don't need to put the logical expressions in brackets.)

Is this code necessary?
    public override bool Equals(System.Object obj)
{
// If parameter is null return false.
if (obj == null)
{
returnfalse;
}

// If parameter cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if ((System.Object)p == null)
{
returnfalse;
}

// Return true if the fields match:
return (x == p.x) && (y == p.y);
}

Is the first test for null necessary?

When casting the object as the class type, it will make 'p' null if 'obj' is null and will yeild the same end result.

I can't see why the first test is necessary.

How about this:

    public override bool Equals(System.Object obj)
{
// If parameter is null or cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if ((System.Object)p == null)
{
returnfalse;
}

// Return true if the fields match:
return (x == p.x) && (y == p.y);
}
"Overriding operator == in non-immutable types is not recommended." Why Not?
The docs give a one line sentence saying we probably should not override the == operator. That's a nice thing to say, but why not? If I can compare String objects to test for value equality, why not a Point object? And so what if I made my Point class immutable?

Maybe there's some abstract philosophies embedded in that statement, but what are the concrete pitfalls in doing so? I'm interested in the academic answer too, but it only seems natural to use "equal signs" to test for the equality between two different objects.

If we have to choose who "owns" the meaning of "==", either value content equality or reference equality, it seems it should be the one used most or more commonly understood by most people. ReferenceEquals() is already defined and seems to satisfy the more nuanced question of equality between two object references.