Наборы HashSet не сохраняют уникальность элементов, если вы изменяете их идентификатор

При работе с HashSetsв C #я недавно столкнулся с досадной проблемой:HashSetsне гарантируют уникальность элементов; они не Сеты. Что они действительно гарантируют, так это то, что при вызове Add(T item)элемент не добавляется, если для любого элемента в наборе item.equals(that)есть true. Это больше не действует, если вы манипулируете элементами, уже входящими в набор. Небольшая программа, демонстрирующая (копипасту с моего Linqpad):

void Main()
{
    HashSet<Tester> testset = new HashSet<Tester>();
    testset.Add(new Tester(1));
    testset.Add(new Tester(2));
    foreach(Tester tester in testset){
      tester.Dump();
    }
    foreach(Tester tester in testset){
      tester.myint = 3;
    }
    foreach(Tester tester in testset){
      tester.Dump();
    }
    HashSet<Tester> secondhashset = new HashSet<Tester>(testset);
    foreach(Tester tester in secondhashset){
      tester.Dump();
    }
}

class Tester{
  public int myint;

  public Tester(int i){
    this.myint = i;
  }

  public override bool Equals(object o){
    if (o== null) return false;
    Tester that = o as Tester;
    if (that == null) return false;
    return (this.myint == that.myint);
  }

  public override int GetHashCode(){
    return this.myint;
  }

  public override string ToString(){
    return this.myint.ToString();
  }
}

Он с радостью манипулирует элементами в коллекции, чтобы они были равными, отфильтровывая их только при построении нового HashSet. Что рекомендуется, когда я хочу работать с наборами, где мне нужно знать, что записи уникальны? Свернуть мой собственный, где Add (T item )добавляет копию элемента, а нумератор перечисляет копии содержащихся элементов? Это создает проблему, заключающуюся в том, что каждый содержащийся элемент должен быть глубоко копируемым -, по крайней мере, в тех его элементах, которые влияют на его равенство.

Другим решением было бы свернуть свое собственное и принять только элементы, которые реализуют INotifyPropertyChanged, и предпринять действия по событию для повторной -проверки на равенство, но это кажется серьезным ограничением, не говоря уже о большом количестве работы и потере производительности при капот.

Еще одно возможное решение, о котором я подумал, - убедиться, что все поля доступны только для чтения или константы в конструкторе. Все решения, кажется, имеют очень большие недостатки. Есть ли у меня другие варианты?

6
задан Joe 10 July 2012 в 12:51
поделиться