HashSet我的类不包含问题

时间:2012-04-14 16:29:39

标签: c# class hashmap equality hashset

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

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时返回false。我在==的实施中遗漏了什么?

4 个答案:

答案 0 :(得分: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个字节长,所以我可能会把它变成一个不可变的结构。

答案 1 :(得分:2)

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

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

您应该,几乎总是同时实施GetHashCodeEquals,或者不执行任何一项。

答案 2 :(得分:0)

您还需要覆盖GetHashCode以使字典生效。

答案 3 :(得分:0)

你也必须覆盖GetHashCode() - 这与覆盖Equals密切相关。字典正在使用GetHashCode()来确定值将落入哪个bin中 - 只有在该bin中找到合适的项目时,它才会检查项目的实际相等性。