При работе с 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, и предпринять действия по событию для повторной -проверки на равенство, но это кажется серьезным ограничением, не говоря уже о большом количестве работы и потере производительности при капот.
Еще одно возможное решение, о котором я подумал, - убедиться, что все поля доступны только для чтения или константы в конструкторе. Все решения, кажется, имеют очень большие недостатки. Есть ли у меня другие варианты?