简体   繁体   English

HashSet我的班级没有问题

[英]HashSet my class doesn't contain issue

I have a class that is similar to this: 我有一个与此类似的课程:

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;
    }
}

This works in HashSet<Int16_2D> . 这适用于HashSet<Int16_2D> However in Dictionary<Int16_2D, myType> , .ContainsKey returns false when it shouldn't. 但是,在Dictionary<Int16_2D, myType>.ContainsKey返回false。 Am I missing something in my implementation of == ? 我在实现==缺少什么吗?

For a class to work in a hash table or dictionary, you need to implement GetHashCode() ! 为了使一个类在哈希表或字典中工作,您需要实现GetHashCode() I have no idea why it's working in HashSet; 我不知道为什么它在HashSet中工作; I would guess it was just luck. 我想那只是运气。

Note that it's dangerous to use mutable fields for calculating Equals or GetHashCode() . 请注意, 使用可变字段来计算Equals或GetHashCode()是危险的 Why? 为什么? Consider this: 考虑一下:

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!

In other words, when you set xa = 3; 换句话说,当您设置xa = 3; you're changing x's hash code. 您正在更改x的哈希码。 But x's location in the hash table is based on its old hash code, so x is basically lost now. 但是x在哈希表中的位置基于其旧的哈希码,因此x现在基本上已经丢失。 See this in action at http://ideone.com/QQw08 请访问http://ideone.com/QQw08实际操作

Also, as svick notes, implementing Equals does not implement == . 此外,正如svick所指出的,实现Equals不会实现== If you don't implement == , the == operator will provide a reference comparison, so: 如果不实现== ,则==运算符将提供参考比较,因此:

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

In conclusion, you're better off making this an immutable type; 总之,最好将其设为不可变类型。 since it's only 4 bytes long, I'd probably make it an immutable struct. 因为它只有4个字节长,所以我可能会将其设为不可变的结构。

You need to override GetHashCode() . 您需要重写GetHashCode() The fact that it works with HashSet<T> is probably just a lucky coincidence. 它与HashSet<T>一起使用的事实可能只是幸运的巧合。

Both collections use the hash code obtained from GetHashCode to find a bucket (ie. list of objects), where the object should be placed. 这两个集合都使用从GetHashCode获得的哈希码来查找存储区(即对象列表),应将对象放置在其中。 Then it searches that bucket to find the object, and uses Equals to ensure equality. 然后,它将搜索该存储桶以找到对象,并使用Equals来确保相等。 This is what gives the nice fast lookup properties of the Dictionary and HashSet. 这就是给Dictionary和HashSet提供不错的快速查找属性的原因。 However, this also means, that if GetHashCode is not overridden so that it corresponds to the types Equals method, you will not be able to find such an object in one of the collections. 但是,这也意味着,如果不重写GetHashCode ,使其对应于Equals方法类型,则将无法在集合之一中找到这样的对象。

You should, almost always, implement both GetHashCode and Equals , or none of them. 您几乎应该始终实现GetHashCodeEquals ,或者都不实现。

您还需要重写GetHashCode才能使字典正常工作。

You have to override GetHashCode() as well - this goes hand in hand with overriding Equals . 您还必须重写GetHashCode() -这与重写Equals Dictionary is using GetHashCode() to determine what bin a value would fall into - only if a suitable item is found in that bin it checks on actual equality of the items. 字典使用GetHashCode()确定某个值将属于哪个bin-仅在该bin中找到合适的项目时,它才会检查这些项目的实际相等性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM