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
?
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.
See more on this question at Stackoverflow