I have a problem with hashsets at the moment. I have classes which are immutable and contain just one item, when I add two different classes with the same data to a hashset, I get them both in the set. This is weird, because I've overloaded Equals and GetHashCode on both the base class and the superclass.
public abstract class Contact :IEquatable<Contact>
{
public readonly BigInteger Id;
public Contact(BigInteger id) { this.Id = id; }
public abstract bool Equals(Contact other);
public abstract int GetHashCode();
public abstract bool Equals(object obj);
}
And the inheriting class:
public class KeyOnlyContact :Contact, IEquatable<KeyOnlyContact>
{
public KeyOnlyContact(BigInteger id) :base(id) { }
public override bool Equals(object obj)
{
if (obj is KeyOnlyContact)
开发者_运维知识库 return Equals(obj as KeyOnlyContact);
else if (obj is Contact)
return Equals(obj as Contact);
else
return (this as object).Equals(obj);
}
public override bool Equals(Contact other)
{
if (other is KeyOnlyContact)
return Equals(other as KeyOnlyContact);
else
return (this as object).Equals(other as object);
}
public bool Equals(KeyOnlyContact other)
{
return other.Id.Equals(Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
As you can see, all the real work is deferred to the BigInteger which is the id. This is a .net class and I have confirmed I don't get duplicate if I just add BigInteger to a hashset.
To clarify:
BigInteger a;
HashSet<Contact> set;
set.add(new KeyOnlyContact(a));
set.add(new KeyOnlyContact(a));
set.Count == 2
public abstract int GetHashCode();
You have accidentally re-declared GetHashCode
(method-hiding). Remove this declaration and it might start working. When your derived classed override GetHashCode
, they are providing this version - they aren't overriding object.GetHashCode
, which is what is required.
If you want an abstract GetHashCode
, perhaps:
public sealed override int GetHashCode() { return GetHashCodeImpl(); }
protected abstract int GetHashCodeImpl();
Now the derived types must provide GetHashCodeImpl
, and they are all mapped to object.GetHashCode
.
精彩评论