2010-04-29 5 views
2

У меня проблема с хэшетами на данный момент. У меня есть классы, которые неизменяемы и содержат только один элемент, когда я добавляю два разных класса с одинаковыми данными в хэшсет, я получаю их оба в наборе. Это странно, потому что я перегрузил Equals и GetHashCode как для базового класса, так и для суперкласса.Дублирующие элементы в hashset

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

И наследующий класс:

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

Как вы можете видеть, вся настоящая работа откладывается на BigInteger, который является идентификатором. Это класс .net, и я подтвердил, что не получаю дубликат, если просто добавлю BigInteger к hashset.

Для уточнения:

BigInteger a; 
HashSet<Contact> set; 

set.add(new KeyOnlyContact(a)); 
set.add(new KeyOnlyContact(a)); 

set.Count == 2 
+0

BTW, включите предупреждения, и вы должны увидеть: «Warning [n]» Foo.GetHashCode() 'скрывает объект унаследованного элемента .GetHashCode()'. Чтобы текущий член переопределил эту реализацию, добавьте ключевое слово переопределения В противном случае добавьте новое ключевое слово. " –

+0

У меня есть предупреждения, к сожалению, у меня также есть предупреждения о незарегистрированных общедоступных методах, которые являются постоянной задачей, которая позволяет хоронить полезные предупреждения в раздражающих предупреждениях документации. Думаю, я могу изменить этот вариант! – Martin

ответ

10
public abstract int GetHashCode(); 

Вы случайно повторно объявлены GetHashCode (метод скрытия). Удалите это объявление, и оно может начать работать. Когда ваш производный класс override GetHashCode, они предоставляют этой версии - они не являются, переопределяя object.GetHashCode, что и является обязательным.

Если вы хотите абстрактную GetHashCode, возможно:

public sealed override int GetHashCode() { return GetHashCodeImpl(); } 
protected abstract int GetHashCodeImpl(); 

Теперь производные типы должны обеспечить GetHashCodeImpl, и все они отображаются в object.GetHashCode.

+0

bah, который скрывает метод, а не требует, чтобы наследующие классы сами реализовывали его. Я пойду и посмотрю, исправляет ли это это – Martin

+0

Да. И это то, что я получаю за кодирование в глупые времена утром в поезде :(Большое спасибо Marc – Martin

+0

@Martin - добро пожаловать. –

Смежные вопросы