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 を実装する要素のみを受け入れ、イベントに対してアクションを実行して等しいかどうかを再確認することですが、これは非常に制限されているように見えます。 .
私が考えたさらに別の可能な解決策は、コンストラクターですべてのフィールドが読み取り専用または const であることを確認することです。すべてのソリューションには、非常に大きな欠点があるようです。他に選択肢はありますか?