C# 字典中可以使用什么作为键?

问题描述 投票:0回答:4

我来自一个Python世界,其中只有可散列的对象才可以用作字典的键。 C#中是否有类似的限制?您可以使用自定义类型作为字典键吗?

c# dictionary types custom-type
4个回答
19
投票

字典键的要求是它是可比较的和可散列的。这在 .NET 中一直是海龟,每种类型(指针类型除外)都派生自 System.Object,并且由于其 Equals() 方法,它总是具有可比性。并且由于其 GetHashCode() 方法而可散列。因此任何 .NET 类型都可以自动用作密钥。

如果你想使用自己的类型作为键,那么你只需要在想要重新定义对象标识时做一些特殊的事情。换句话说,如果您需要两个不同对象相等的能力。然后,您可以重写 Equals() 方法,通常比较对象的字段。然后你还必须重写GetHashCode(),相等的对象必须生成相同的哈希码。

如果类型无法更改,或者您想要自定义行为,特别是字典的行为,那么您可以将自定义 IEqualityComparer<> 传递给构造函数。请记住,您使用自己的 GetHashCode() 生成的哈希码的质量决定了字典的效率。


3
投票

是的,键的重要之处在于它们实现(或具有良好的默认实现)

GetHashCode
Equals
Dictionary<T, K>
实现可以利用通用
IEqualityComparer<T>

所有自定义类型都将附带

GetHashCode
Equals
的默认实现,因为它们是
object
的成员,但是,该默认值可能并不总是与您的类型相关。

字典首先尝试获取哈希码来确定值将进入的存储桶。如果存在哈希冲突,它会退回到相等(我认为)。

请注意,您使用的密钥类型(

class
struct
、原始类型等)可能会产生不同的性能特征。在我们的代码库中,我们发现
GetHashCode
struct
的默认实现并不像我们自己重写它那么快。我们还发现,嵌套字典在访问时间方面比具有复合键的单个字典表现更好。


2
投票

可以,只需实现 IEqualityComparer 接口,重写 GetHashCode 和 Equals 即可。


0
投票

我想补充一点,现在,您可以使用 C#

record
类型作为键。

record
(而不是
class
)的好处是它现在自动为您实现
GetHashCode()
等(通过编译器生成的魔法)。

  • 有关详细信息,请参阅记录(C# 参考)--值相等
  • 请注意,此帮助并未明确说明您可以将它们用作密钥(但我相信您可以)
  • 请注意,如果您对用作键的对象进行变异(更改其属性值),我预计会发生不好的事情,所以不要这样做
© www.soinside.com 2019 - 2024. All rights reserved.