I am trying to create a base record type which will use a different implementation of Equals() for value equality, in that it will compare collection objects using SequenceEqual(), rather than comparing them by reference.
However, the implementation of Equals() doesn't work as I'd expect with inheritance.
In the example below, I have got a derived class which has two different lists. Under the default implementation of equality, these records are different because it is comparing the lists by reference equality, not by sequence equality.
If I override the default implementation of Equals() on the base record to always return true, the unit test will fail, even though the code is calling RecordBase.Equals(RecordBase obj).
public abstract record RecordBase
{
public virtual bool Equals(RecordBase obj)
{
return true;
}
}
public record DerivedRecord : RecordBase
{
public DerivedRecord(ICollection<int> testCollection)
{
TestCollection = testCollection;
}
public ICollection<int> TestCollection { get; init; }
}
public class RecordTests
{
[Fact]
public void Equals_WhenCollectionHasSameValues_ReturnsTrue()
{
var recordTest1 = new DerivedRecord(new List<int>() { 1, 2, 3 });
var recordTest2 = new DerivedRecord(new List<int>() { 1, 2, 3 });
Assert.True(recordTest1.Equals(recordTest2));
}
}
Interestingly, if I change the implementation so that Equals() is implemented on the DerivedRecord, rather than on RecordBase, the unit test will pass.
public record DerivedRecord : RecordBase
{
public DerivedRecord(ICollection<int> testCollection)
{
TestCollection = testCollection;
}
public virtual bool Equals(DerivedRecord obj)
{
return true;
}
public ICollection<int> TestCollection { get; init; }
}
Furthermore, this issue is specific to records: if I change the implementation of the first example to use classes, the two instances will evaluate to being equal and the unit test will pass.
public abstract class RecordBase
{
public virtual bool Equals(RecordBase obj)
{
return true;
}
}
So there is something in trying to override the default implementation of Equals() with records, where the derived records will not inherit the base record's implementation.
Is there a reason for this? Intuitively, it seems like a derived record should be able to inherit a base record's implementation of value based equality. However, I've been reading through the C# 9.0 specification for records and I'm not sure if there is a synthesized implementation which is preventing this, or whether this is even possible using records.
Console.WriteLineinstead ofDebug.Assert. You can see that it returnsfalse.