关于 .Net 中通用字典中的引用类型键的快速问题

Posted

技术标签:

【中文标题】关于 .Net 中通用字典中的引用类型键的快速问题【英文标题】:Quick question about a reference type key in a generic dictionary in .Net 【发布时间】:2011-01-28 04:22:19 【问题描述】:

我有一个可变类,用作通用字典的键。只有当它们的引用相等时,两个键才应该相等。 根据我的阅读,在这种情况下,我不需要重写 Equals、GetHashCode 或实现 IEqualityComparer。

这对吗?

【问题讨论】:

【参考方案1】:

是的。 System.Object 中的默认比较操作使用引用相等。如果这种行为是您想要的,那么默认值应该可以正常工作。

【讨论】:

虽然我确实担心如果有人稍后添加这些覆盖的行为。哈希表中的存储桶将由对象在添加时的哈希计算。如果状态(以及哈希)发生变化,对 Contains() 和 Remove() 等的调用随后会失败。 是的。这总是一个棘手的问题。元素的散列需要一些有关对象的先验知识。即使您提供了自己的覆盖,子类也可以覆盖您的...... 除非你自己覆盖它们,密封它们,并让你的实现调用基础。 @Jon:是的。密封方法并强制您的类+所有子类引用相等和散列工作。不过,在这种情况下,您对子类施加了很大的限制。【参考方案2】:

Yes, this is correct.只要不覆盖,引用就是默认比较。

【讨论】:

【参考方案3】:

我将补充其他人在这里所说的话(是的),但还有一点似乎没有人在这里提到。

当使用泛型集合(字典、列表等)时,您可以覆盖 IEquatable 以提供特定类型的版本,该版本可以进行比较而无需装箱或向上/向下转换。这些泛型集合将在存在时使用此重载进行比较,并且效率更高。

如文档中所述,在实现 IEquatable 时,您仍然需要从 Object 覆盖 Equals/Hashcode。

【讨论】:

很高兴您提到了这一点,因为我在查看反射器后也有同样的想法。让我感到困惑的是需要覆盖 GetHashcode,即使我不会更改等价测试。我会用什么覆盖 GetHashcode?​​span> 【参考方案4】:

正如其他人已经指出的那样,是的,你是对的。事实上,如果你的类型是可变的(它有设置器),你肯定想要覆盖等式成员。但是,如果您想要使用类型中的值进行相等性检查,您可以通过确保没有设置器(只有构造函数设置值)来使您的类型不可变(如String)。或者使用struct

【讨论】:

【参考方案5】:

对于使用 .Net 5 或更高版本的任何人,它都带有一个 ReferenceEqualityComparer 类,您可以将其传递给字典的构造函数。这意味着您无需担心将来有人会覆盖 GetHashCode 和 Equals。

【讨论】:

【参考方案6】:

是的,如果没有指定其他重载,则对两个对象进行 == 比较(或 .Equals)比较它们的引用是正确的。

String s = "a";

object test1 = (object)s;
object test2 = (object)s;

Debug.Assert(test1.Equals(test2));

【讨论】:

你不能override ==,你只能overload它。此外,== 不在通用字典中使用:Equals 和 GetHashCode 是。

以上是关于关于 .Net 中通用字典中的引用类型键的快速问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Json.Net 序列化/反序列化带有自定义键的字典?

字典中的数据类型为unicode

Java中的Hashtable如何根据值获取键?

字典列表中所有键的联合

Python字典的实现原理

.NET 字典中的重复键?