在使用HashSets
C# 时,我最近遇到了一个烦人的问题:HashSets
不保证元素的唯一性;它们不是集合。他们所做的保证是,当被调用时,如果集合中Add(T item)
的任何项目是 ,则不会添加该项目。如果您操作集合中已有的项目,这将不再成立。一个演示的小程序(来自我的 Linqpad 的 copypasta):item.equals(that)
true
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 的元素,并对事件采取行动以重新检查是否相等,但这似乎严重限制,更不用说引擎盖下的大量工作和性能损失.
我想到的另一个可能的解决方案是确保构造函数中的所有字段都是只读的或常量。所有解决方案似乎都有很大的缺点。我还有其他选择吗?