字典包含键比较

3

我正在尝试做以下类似的事情:

class Test
{
     public string Name { get; set;}
     public string Location { get; set;}
     public Test(string name, string location)
     {
         Name = name;
         Location = location;
     }
}

现在,在另一个类的一个方法中,我正在尝试将这些测试类添加到一个Dictionary中,并使用KeyValuePair。
Dictionary<Test,int> resources = new Dictionary<Test,int>();
resources.Add(new Test("First Resource", "Home"), 1);

现在,我想做的并且需要能够做的是:
bool contains = resources.ContainsKey(new Test("First Resource", "Home"));
resources[new Test("First Resource", "Home")] = 2;

目前返回的是false。我该如何让它返回true?

我已经尝试重载Test类的Equals函数,甚至实现了IComparable并进行了自定义比较。

3个回答

4

在您的Test类中,需要重写GetHashCode方法,将以下内容添加到您的类中:

public override int GetHashCode()
{
    return (Name+Location).GetHashCode();
}

这将确保仅当Name和Location的串联相同时,任何两个测试实例才具有相同的哈希值。您可以使用其他策略来实现此目的,但这是最简单的形式。


@KyleUithoven 只需不允许在名称和位置字段中放置任意大的字符串。将这些字段限制为一定的长度即可。 - Candide
@AnthonyPegram:谢谢你的解释,我现在明白你在说什么了。两个不相等的对象可以有相同的哈希码,但这并不意味着它们会返回相等。这项工作由equal函数完成。 - Kyle Uithoven
@Kyle,可以这样想:GetHashCode()返回一个int,这意味着可能有2^32个哈希码。字符字符串的可能性远远超过2^32,因此显然会发生冲突。不过没关系,哈希函数的目标是确保散列表的随机输入具有合理平衡的哈希值分布。 - dlev
@dlev:这就是为什么等值函数存在的原因吗?当哈希码相等时,ContainsKey只会进入等值函数吗?因此,即使有两个不相等的对象具有相同的哈希码,等值函数也会确保它们相等。 - Kyle Uithoven
@Kyle Bingo。GetHashCode()缩小了候选列表,然后Equals()使其落实。 - dlev
显示剩余7条评论

4
您需要在键类中实现GetHashCode Equals,或者在字典的构造函数中提供一个IEqualityComparer<Test> 的实现。

在比较器的情况下,您将在比较器内为Test定义适当的GetHashCodeEquals方法,其中的好处是这些实现不是所有 Test 对象的通用实现,而是可以根据需要自由使用(例如,在字典、哈希集、各种Linq查询等中使用)。通过将相等性和哈希码函数从类中解耦,您可以在需要时自由使用不同的比较器实现。

(有关GetHashCode的一组良好指南,请访问此博客。)


3
字典使用键的GetHashCode来确定在哪个数据桶中存储对象,然后使用Equals确保对象实际上是相等的。换句话说,为了使其工作,您需要为您的类型实现 GetHashCode() Equals
将用于字典键的对象设置为不可变对象被认为是一种良好的做法。如果对象更改,则其哈希码也会更改,您可能无法在字典中找到它。

我尝试实现GetHashCode(),但不知道该返回什么。有什么好的方法吗?将名称和位置转换为整数值并相加? - Kyle Uithoven
@Kyle - 任何返回“相同”对象相同值的内容都可以。对于“不同”的对象返回相同值是可以但不理想的。你建议的方式很好,Ingenu的建议也可以。 - Robert Levy
请参考这个优秀的答案,了解如何实现GetHashCode:https://dev59.com/questions/EnVC5IYBdhLWcg3wihqv#263416 - driis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接