2012-04-14 51 views
0

我有一类就是类似于这样: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。我在执行==时错过了什么吗?

+2

http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c – 2012-04-14 16:31:13

+2

请注意,你并不是真的实现'==','Equals()'是不同的。 – svick 2012-04-14 16:33:02

回答

2

你需要重写GetHashCode()。它与HashSet<T>一起使用的事实可能只是一个幸运的巧合。

两个集合使用来自GetHashCode获得找到一个桶(即对象列表),其中该对象应当放置的哈希码。然后它搜索该存储桶以找到该对象,并使用Equals确保相等。这就是Dictionary和HashSet的快速查找属性。然而,这也意味着,如果GetHashCode不被覆盖,使得其对应类型Equals方法,你将无法在收藏品之一找到这样的对象。

你应该几乎总是同时实现GetHashCodeEquals,或没有。

0

你需要重写GetHashCode以及对字典的工作。

0

你必须重写GetHashCode() - 这与重写Equals并行。 Dictionary正在使用GetHashCode()来确定一个值将落入哪个bin - 只有在该bin中找到合适的项目时,它才会检查项目的实际相等性。

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个字节长,我可能会使它成为一个不可变的结构体。