HashSets nie zachowują unikalności elementów, jeśli zmutujesz ich tożsamość
Podczas pracy zHashSets
w C # niedawno natknąłem się na irytujący problem:HashSets
nie gwarantuj jedności elementów; nie są to zestawy. To, co gwarantują, to kiedyAdd(T item)
jest nazywany, element nie jest dodawany, jeśli dla dowolnego elementu w zestawieitem.equals(that)
jesttrue
. Nie działa to dłużej, jeśli manipulujesz przedmiotami już w zestawie. Mały program, który demonstruje (copypasta z mojego Linqpada):
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();
}
}
Chętnie manipuluje elementami w kolekcji, aby być równym, filtrując je tylko wtedy, gdy zostanie zbudowany nowy HashSet. Co jest godne polecenia, gdy chcę pracować z zestawami, w których muszę wiedzieć, że wpisy są wyjątkowe? Rzuć własne, gdzie Dodaj (element T) dodaje kopię elementu, a moduł wyliczający wylicza kopie zawartych elementów? Stawia to wyzwanie, że każdy zawarty element powinien być głęboko kopiowalny, przynajmniej w jego elementach, które wpływają na jego równość.
Innym rozwiązaniem byłoby przetaczanie własnych i akceptowanie tylko elementów, które implementują INotifyPropertyChanged, i podejmowanie działań w celu ponownego sprawdzenia równości, ale wydaje się to poważnie ograniczające, nie wspominając o dużej ilości pracy i utraty wydajności pod maską .
Jeszcze innym możliwym rozwiązaniem, o którym myślałem, jest upewnienie się, że wszystkie pola są tylko do odczytu lub const w konstruktorze. Wszystkie rozwiązania wydają się mieć bardzo duże wady. Czy mam jakieś inne opcje?