Striezel
Striezel

Reputation: 3758

C# - equality operator with list of interface type not working as expected

Consider the following code, where ClassOne is a class derived from IClass:

List<IClass> list = new List<IClass>();
list.Add(new ClassOne("foo", "bar"));
list.Add(new ClassOne("baz", "bam"));

List<IClass> list2 = new List<IClass>();
list2.Add(new ClassOne("foo", "bar"));
list2.Add(new ClassOne("baz", "bam"));

if (list == list2)
    Console.WriteLine("Lists are equal.");
else
    Console.WriteLine("Lists are NOT equal.");

The equality operator returns false (i.e. lists do not match), besides the fact the the operator ==, operator !=, Equals(ClassOne), Equals(object) and GetHashCode() have been implemented/overridden for ClassOne. Why is that? I would expect the equality operator to return true. Are there any other methods/interfaces that must be implemented for the == operator to work as expected?

For reference, here's the implementation of ClassOne and IClass:

public interface IClass
{
    string getA();
    string getB();
} //interface


public class ClassOne : IClass, IEquatable<ClassOne>
{
    public ClassOne(string a, string b)
    {
        strA = a;
        strB = b;
    }

    public string getA()
    {
        return strA;
    }

    public string getB()
    {
        return strB;
    }

    public bool Equals(ClassOne other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        if (!string.Equals(strA, other.strA))
            return false;
        return string.Equals(strB, other.strB);
    }

    public override bool Equals(object other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        if (other is ClassOne)
        {
            ClassOne c1 = (ClassOne)other;
            return Equals(c1);
        }
        //not ClassOne, so it is not equal
        return false;
    }

    public override int GetHashCode()
    {
        int hc_a = -1;
        if (null != strA)
            hc_a = strA.GetHashCode();
        int hc_b = -1;
        if (null != strB)
            hc_b = strB.GetHashCode();
        return hc_a ^ hc_b;
    }

    public static bool operator ==(ClassOne left, ClassOne right)
    {
        if (ReferenceEquals(left, right)) return true;
        if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
            return false;
        return left.Equals(right);
    }

    public static bool operator !=(ClassOne left, ClassOne right)
    {
        return !(left == right);
    }

    private string strA, strB;
} //class

Any help or hints in the right direction will be appreciated. Thanks.

Upvotes: 2

Views: 1454

Answers (2)

D Stanley
D Stanley

Reputation: 152566

Why is that? I would expect the equality operator to return true.

Not correct - the == operator (and Equals()) are not defined on List<T> to check the equality of its contents - it defaults to reference equality from the operator defined on object. Since the two lists are different objects, == returns false.

You can use the Linq SequenceEqual method to determine if two lists contain equal objects in the same order:

if (list.SequenceEqual(list2))
    Console.WriteLine("Lists are equal.");
else
    Console.WriteLine("Lists are NOT equal.");

Upvotes: 8

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

Because the == operator is not overloaded for the List<T> class. == for lists is simply reference equality. Even two List<int> objects that hold the same ints are not equal, etc.

If you ask whether list == list2, the compiler will call the == operator for List<T>, and the designer of the List<T> class have decided that two lists are only equal if both refer to the same list. In other words:

public class List<T> {

    public static bool operator ==(List<T> left, List<T> right) {
        return ReferenceEquals(left, right);
    }

}

(Evidently there is more content in the List<T> class, and since it uses reference equality, one does not have to overload the operator).

Upvotes: 3

Related Questions