Rid*_*his 5 c# inheritance equality record
我正在尝试创建一个基本记录类型,它将使用Equals()值相等的不同实现,因为它将使用比较集合对象SequenceEqual(),而不是通过引用比较它们。
但是,Equals() 的实现并不像我期望的继承那样工作。
在下面的示例中,我有一个派生类,它有两个不同的列表。在相等性的默认实现下,这些记录是不同的,因为它是通过引用相等性而不是序列相等性来比较列表。
Equals()如果我覆盖基本记录上的默认实现以始终返回true,单元测试将失败,即使代码正在调用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));
}
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我更改实现,以便Equals()在 上实现DerivedRecord,而不是在 上实现RecordBase,则单元测试将通过。
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; }
}
Run Code Online (Sandbox Code Playgroud)
此外,这个问题特定于记录:如果我将第一个示例的实现更改为使用类,则两个实例将评估为相等并且单元测试将通过。
public abstract class RecordBase
{
public virtual bool Equals(RecordBase obj)
{
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,尝试覆盖Equals()记录的默认实现是有问题的,其中派生记录不会继承基本记录的实现。
是否有一个原因?直观上,派生记录似乎应该能够继承基本记录的基于值的相等实现。但是,我一直在阅读C# 9.0 记录规范,并且不确定是否有一个综合实现可以防止这种情况,或者是否可以使用记录来实现这一点。
不幸的是,记录的行为并不如您所期望的那样。
当您声明记录时,您可以免费获得相等检查运算符和方法。
您的基类只返回true,但是当您将派生记录声明为 a 时record,您还会在其中获得一个相等性检查方法,如下所示:
public virtual bool Equals(DerivedRecord other)
{
return (object)this == other || (base.Equals(other) &&
EqualityComparer<ICollection<int>>.Default.Equals(
this.TestCollection,
other.TestCollection));
}
Run Code Online (Sandbox Code Playgroud)
由于EqualityComparer<ICollection<int>>.Default.Equals进行了简单的引用比较,因此两个列表虽然具有相同的内容,但不被视为相等,因此您会返回false.
如果将类型更改为与class相反record,则不会添加编译器生成的Equals方法和相关运算符,并且您将保留基类中返回的类型true。
但对于record类型,您将为每个继承级别和类型获取该方法。这也是为什么直接在派生记录类型上实现它也可以根据您的预期“工作”,因为这样编译器就不会为您生成记录类型。
| 归档时间: |
|
| 查看次数: |
1429 次 |
| 最近记录: |