我发现很多关于Equals重写和==运算符重载之间差异的讨论,但似乎有一些关于我们应该或不重写默认的相等行为的问题,这使我怀疑这样做的好方法。
以下是我的理解,请告诉我你是否有错误:
1)==不推荐非不可变类型的重载(为什么??),并且对于不可变类型(也就是DDD的值对象)非常有用,如果值相同但不是,则== comparaison返回true引用。
2)Equals(和GetHashCode)也应该在不可变类型中被覆盖,以便对类型内相关字段的每个值进行良好的比较。
3)实体的平等如何?
覆盖Equals并仅比较id属性是一个好主意吗?或者我应该让比较引用的默认对象行为?
对于这两个选项,我认为如果我遵循规则,我应该在线程上下文中只有一个特定实体的实例,结果应该是相同的,但是有一个缺点或优点我应该注意这些选项吗?
答案 0 :(得分:6)
在我看来,正确的平等操作是面向对象世界中最被低估的工具之一。是的,你应该在有意义的地方完全实现它们,它会使你的程序更加简洁。
E.g。比较
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 code analysis rule。
平等操作对值对象最有用。还重写相等运算符,使相等比较看起来很自然。
平等操作的实现是微不足道的:考虑所有数据字段但忽略计算属性。这将创建纯粹基于内容的平等操作。
由于在值对象上实现相等操作是机械的,因此有library called Equ自动为您执行此操作(我自己编写)。它将在静态实例化时创建相等操作,这些操作与手动编写的Equals
和GetHashCode
实现具有相同的运行时性能。
对于实体,它会变得有点棘手。问题在于,从域名的角度来看,平等意味着什么是 。
显然,具有不同ID的两个Customer
实体不相等。但那是关于它的。两个Customer
实体具有相同的ID,但处于不同的状态?困难的问题。
好消息是这种功能并不是真正需要的。所以我的建议是:不要对实体实施平等操作。