Search code examples
c#classrecordiequatable

Do Record types' == operator perform equivalent comparisons to the 'Equals' method in classes implementing IEquatable<T>?


I have a class named 'Clock' that implements the IEquatable interface. I've implemented the 'Equals' method in my class to compare two objects like this:

public bool Equals(Clock? other)
{
    return _hours == other?._hours && _minutes == other._minutes;
}

When I changed my class to a record type and replaced the Equals method with the == operator, the results remained the same. Can I conclude that the Equals method in my class essentially performs the same comparison as the == operator does for record types?

Scenario one: I have two objects of Clock class like this and want to check value equality of two objects using Equals method which I added to my class.

Clock clock1 = new(2, 10);
Clock clock2 = new(2, 10);
if (clock2.Equals(clock1))
{
    Console.WriteLine("Equal");
}

Second scenario: changing my class to record type and comparing two objects with == operator

Clock clock1 = new(2, 10);
Clock clock2 = new(2, 10);
if (clock1 == clock2)
{
   Console.WriteLine("Equal");
}

In the both cases they return true. I wonder does Equals method does exact same thing as == ?


Solution

  • Yes, with a few basic assumptions, == for a record is the same as the Equals you wrote. From the proposal for records,

    The synthesized Equals(R?) returns true if and only if each of the following are true:

    • other is not null, and
    • For each instance field fieldN in the record type that is not inherited, the value of System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN) where TN is the field type, and
    • If there is a base record type, the value of base.Equals(other) (a non-virtual call to public virtual bool Equals(Base? other)); otherwise the value of EqualityContract == other.EqualityContract.

    The record type includes synthesized == and != operators equivalent to operators declared as follows:

    public static bool operator==(R? left, R? right)
        => (object)left == right || (left?.Equals(right) ?? false);
    public static bool operator!=(R? left, R? right)
        => !(left == right);
    

    The Equals method called by the == operator is the Equals(R? other) method specified above.

    Your Clock.Equals satisfy the conditions for the synthesised Equals to return true if we assume a few basic things, such as:

    • _hours and _minutes are the only fields of Clock
    • the types of _hours and _minutes are ints, or anything such that the default equality comparer for that type returns the same thing as comparing them with ==.
    • Clock doesn't have derived records (EqualityContract will always be equal)