基于C#简单值的DTO比较(以及GetHashCode困境)

本文关键字:以及 GetHashCode 困境 比较 DTO 简单 基于 | 更新日期: 2023-09-27 18:31:54

我知道已经有很多关于GetHashCode的讨论,但他们通常提供的建议对于解决一个相对简单的问题并不是很有利......

我有一个简单的DTO类,其中包含许多各种类型的自动实现属性,我想对此类的两个实例执行简单的基于值的比较。 (主要目的是确定在不同时间点生成的实例之间的任何更改。

通过添加适当的方法,这可以很容易地完成。但碰巧的是,这正是 Equals() 方法和 IEquatable 接口应该用于的。所以我认为,与其仅仅实现一个非标准的自定义方法,不如实现 IEquatable......

现在问题来了:MSDN文档说,为了实现IEquatable,你还应该覆盖Object.Equals()。这是有道理的。但是如果你覆盖 Object.Equals(),你也应该覆盖 HetHashCode()。仍然不是真正的问题,我在这里找到了各种关于如何计算它的讨论,如果你决定这样做。

但是,我读过的文档和所有讨论都说 GetHashCode() 输出应该保持稳定,因此不建议在可变对象上覆盖它......我能理解这一点。(不过,让我注意一下,我无意将此类用作字典键,这似乎是主要问题......

但是,我拥有的DTO类是可变的。使其不可变需要使用笨拙的构造函数或具有大量参数或构建器模式的静态工厂方法,并且会阻止您使用相当方便的对象初始值设定项语法。总而言之,这真的不值得付出努力和不便。

那现在怎么办?我仍然想添加一种比较内容的方法,但现在我不再真正确定推荐的最佳实践是什么。

编辑:

忘了补充一点,我还看到了有关基于类中一组不可变字段实现 GetHashCode 的建议。但是,由于我的所有属性都是自动实现和可修复的,因此从技术上讲,它们都可以更改......

更新:

感谢您的回答。所以基本上我不需要太担心 GetHashCode,只要"我知道我在做什么"——这意味着该类不会在键控集合中使用。

也感谢您对IEqualityComparer的建议,我可能会试一试。

选择"接受"的答案有点困难,因为它们都是很好的答案,但我必须选择一个......

基于C#简单值的DTO比较(以及GetHashCode困境)

有人

可能会说你的DTO根本不应该有任何行为,包括EqualsGetHashCode。如果要比较这些类型的对象,请使用在其他地方定义的方法。这很好地解决了问题。

但是假设您对 DTO 没有那么严格,那么您必须覆盖Equals(Object) .你不一定必须实现IEquatable,但如果你愿意,你可以。而且,是的,如果你覆盖Equals(Object),那么你真的应该覆盖GetHashCode.

是的,GetHashCode依赖于可变字段通常是一个坏主意。但是,如果您不会使用键控集合中的对象,请不要担心。继续做你需要做的事情。请记住:MSDN 中的准则是准则。如果你知道规则并了解违反规则的风险 - 并且你愿意承担后果 - 那么继续去做吧。

只要对象用作哈希表中的键,哈希代码只需要稳定。如果您不将其用作键,或者在添加后不对其进行更改,则可以。

如果不将其用作哈希表键,则根本不需要覆盖GetHashCode。锐化器可以生成所有相等成员。这是我通常做的事情。