等于覆盖和 == 重载,对于值对象与实体

本文关键字:于值 对象 实体 重载 覆盖 于覆盖 | 更新日期: 2023-09-27 18:35:20

我发现了很多关于 Equals 覆盖和 == 运算符重载之间差异的讨论,但似乎有一些关于我们何时应该或不应该覆盖默认相等行为的不满,这让我怀疑这样做的好方法。

以下是我的理解,请告诉我你是否有问题:

1) == 重载不会对不可变类型(为什么 ??)重新

推荐,并且对于不可变类型(也称为 DDD 的值对象)很有用,如果值相同但引用不相同,则使 == comparison 返回 true。

2)等于(和GetHashCode)也应该在不可变类型中被覆盖,以便对类型内相关字段的每个值进行良好的比较。

3)实体的平等怎么样?

覆盖等于并仅比较 id 属性是个好主意吗?还是我应该让比较引用的默认对象行为?

对于这两个选项,我认为如果我遵循在线程上下文中应始终只有一个特定实体的实例的规则,则结果应该是相同的,但是我应该注意这些选项之一是否有一些缺点或优点?

等于覆盖和 == 重载,对于值对象与实体

动机

在我看来,适当的相等运算是面向对象世界中最被低估的工具之一。是的,你绝对应该在有意义的地方实现它们,这将使你的程序更加简洁。

例如比较

Assert.Equal(expectedAddress.Street, address.Street);
Assert.Equal(expectedAddress.City, address.City);
Assert.Equal(expectedAddress.Zip, address.Zip);
Assert.Equal(expectedAddress.State, address.State);
Assert.Equal(expectedAddress.Country, address.Country);

Assert.Equal(expectedAddress, address);

当您具有深度嵌套的值对象时,这种情况变得更加极端。

何时使用

为了不产生尴尬的行为,请只在不可变类型上实现相等操作。这很重要,因为例如,哈希映射将无法在可变类型中正常工作(想想当对象的哈希代码在哈希映射中时发生更改时会发生什么)。

单独实现Equals对于某些可变类型可能是有意义的,但通常不鼓励这样做,例如通过Microsoft代码分析规则。

值对象

相等运算对值对象最有用。还要重写相等运算符,使相等比较看起来很自然。

相等运算的实现很简单:考虑所有数据字段,但忽略计算属性。这将创建纯粹基于内容的平等操作。

由于在值对象上实现相等运算是机械的,因此有一个名为 Equ 的库可以自动为您执行此操作(这是我自己编写的)。它将在静态实例化时创建相等操作,这些操作具有与手动编写的EqualsGetHashCode实现相同的运行时性能。

实体

对于实体,它会变得更加棘手。问题在于,从领域的角度来看,平等通常并不真正清楚是什么意思。

显然,具有不同 ID 的两个Customer实体并不相等。但仅此而已。两个 Customer 个具有相同 ID 但处于不同状态的实体是否相等?困难的问题。

好消息是,这种功能并不是真正需要的。所以我的建议是:不要对实体实施平等操作。