0

我有一个与此类似的课程:

public class Int16_2D
{
    public Int16 a, b;

    public override bool Equals(Object other)
    {
        return other is Int16_2D &&
        a == ((Int16_2D)other).a &&
        b == ((Int16_2D)other).b;
    }
}

这适用于HashSet<Int16_2D>. 然而在Dictionary<Int16_2D, myType>,.ContainsKey不应该的时候返回 false 。我在执行过程中遗漏了什么==吗?

4

4 回答 4

3

要让一个类在哈希表或字典中工作,您需要实现GetHashCode()! 我不知道为什么它在 HashSet 中工作;我猜这只是运气。

请注意,使用可变字段来计算 Equals 或 GetHashCode() 是危险的。为什么?考虑一下:

var x = new Int16_2D { a = 1, b = 2 };
var set = new HashSet<Int16_2D> { x };

var y = new Int16_2D { a = 1, b = 2 };
Console.WriteLine(set.Contains(y));   // True

x.a = 3;
Console.WriteLine(set.Contains(y));   // False
Console.WriteLine(set.Contains(x));   // Also false!

换句话说,当您设置时,x.a = 3;您正在更改 x 的哈希码。但是 x 在哈希表中的位置是基于其旧的哈希码,所以 x 现在基本丢失了。在http://ideone.com/QQw08上查看此操作

此外,正如 svick 所说,实施Equals不实施==. 如果不实现====运营商会提供参考比较,所以:

var x = new Int16_2d { a = 1, b = 2 };
var y = new Int16_2d { a = 1, b = 2 };
Console.WriteLine(x.Equals(y));             //True
Console.WriteLine(x == y);                  //False

总之,您最好将其设为不可变类型;由于它只有 4 个字节长,我可能会将其设为不可变结构。

于 2012-04-14T16:33:00.613 回答
2

您需要覆盖GetHashCode(). 它适用的事实HashSet<T>可能只是一个幸运的巧合。

两个集合都使用从中获得的哈希码GetHashCode来查找应该放置对象的存储桶(即对象列表)。然后它搜索该存储桶以找到对象,并使用它Equals来确保相等。这就是 Dictionary 和 HashSet 的快速查找属性。但是,这也意味着,如果GetHashCode没有被覆盖以使其对应于 typesEquals方法,您将无法在其中一个集合中找到这样的对象。

您应该几乎总是同时实现GetHashCodeand Equals,或者一个都不实现。

于 2012-04-14T16:32:02.900 回答
0

您还需要覆盖GetHashCode才能使字典正常工作。

于 2012-04-14T16:31:56.343 回答
0

您还必须覆盖GetHashCode()- 这与覆盖齐头并进Equals。字典GetHashCode()用于确定一个值将落入哪个 bin - 只有在该 bin 中找到合适的项目时,它才会检查项目的实际相等性。

于 2012-04-14T16:32:06.837 回答