Reputation: 46178
A parent type:
public class IdObject : IComparable<IdObject>, IEquatable<IdObject>
{
public int id { get; set; }
public bool Equals(IdObject other)
{
if (other == null) return this == null;
if (this == null) return false;
var test = other.id.CompareTo(this.id);
return other.id.CompareTo(this.id) == 0;
}
public int CompareTo(IdObject other)
{
return other.id.CompareTo(this.id);
}
}
A child:
public class NamedObject : IdObject
{
public string name { get; set; }
}
Comparing lists of IdObject
s
var list1 = new List<IdObject>()
{
new IdObject() { id = 42 },
new IdObject() { id = 43 }
};
var list2 = new List<IdObject>()
{
new IdObject() { id = 43 },
new IdObject() { id = 42 }
};
list1.Sort();
list2.Sort();
var test = list1.SequenceEqual(list2); // True
Comparing lists of Named
s
var list1 = new List<NamedObject>()
{
new NamedObject() { id = 42 },
new NamedObject() { id = 43 }
};
var list2 = new List<NamedObject>()
{
new NamedObject() { id = 43 },
new NamedObject() { id = 42 }
};
list1.Sort();
list2.Sort();
var test = list1.SequenceEqual(list2); // False
I realized that IdObject::Equals
is not called through a NamedObject
context.
Am I doing something wrong ?
Isn't supposed to call the inherited Equals
?
How can I use the parent's Equals
?
Upvotes: 1
Views: 672
Reputation: 1500745
Basically, you've got a problem because your type doesn't override object.Equals(object)
in a way consistent with your IEquatable<T>
implementation and you're dealing with a collection of the subclasses.
SequenceEqual
will be using EqualityComparer<NamedObject>.Default
. That will check whether NamedObject
implements IEquatable<NamedObject>
- and will find that it doesn't, so it will fall back to calling object.Equals(object)
. You can see this here:
using System;
using System.Collections.Generic;
public class Base : IEquatable<Base>
{
public override bool Equals(object other)
{
Console.WriteLine("Equals(object)");
return false;
}
public bool Equals(Base other)
{
Console.WriteLine("Equals(Base)");
return false;
}
public override int GetHashCode() => 0;
}
public class Derived : Base
{
}
public class Test
{
static void Main()
{
var comparer = EqualityComparer<Derived>.Default;
Console.WriteLine(comparer.Equals(new Derived(), new Derived()));
}
}
You don't override object.Equals(object)
, so you've effectively got reference equality.
I would recommend that you override object.Equals(object)
and object.GetHashCode()
in your base class.
You could then also implement IEquatable<NamedObject>
in NamedObject
, just delegating to the base implementation or (better) checking the name as well, unless you really don't want that to be taken into account.
Upvotes: 7