阿罗哈,HashSet的<T> .RemoveWhere()和GetHashCode()
这里有一个简单的类,它覆盖的GetHashCode:
class OverridesGetHashCode
{
public string Text { get; set; }
public override int GetHashCode()
{
return (Text != null ? Text.GetHashCode() : 0);
}
// overriding Equals() doesn't change anything, so I'll leave it out for brevity
}
当我创建一个类的实例,将其添加到HashSet,然后改变它的Text属性,例如:
var hashset = new HashSet<OverridesGetHashCode>();
var oghc = new OverridesGetHashCode { Text = "1" };
hashset.Add(oghc);
oghc.Text = "2";
那么这不起作用:
var removedCount = hashset.RemoveWhere(c => ReferenceEquals(c, oghc));
// fails, nothing is removed
Assert.IsTrue(removedCount == 1);
而且也没有这样的:
// this line works, i.e. it does find a single item matching the predicate
var existing = hashset.Single(c => ReferenceEquals(c, oghc));
// but this fails; nothing is removed again
var removed = hashset.Remove(existing);
Assert.IsTrue(removed);
我猜它在内部使用时,项目被插入,如果这是真的,这是 理解的hashset.Contains(oghc)不工作时产生的哈希值。 我也猜测它通过它的哈希代码查找项目,如果它找到匹配项,只有它检查谓词,这可能是第一次测试失败的原因(再次,我只是在这里猜测)。 但是为什么最后一次测试失败,我只是从哈希集合中取出那个对象?我是否错过了某些东西,这是从HashSet中移除某些东西的错误方法吗?
感谢您花时间阅读本文。
UPDATE:为了避免混淆,这里的equals()方法:
protected bool Equals(OverridesGetHashCode other)
{
return string.Equals(Text, other.Text);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((OverridesGetHashCode) obj);
}
您应该看看Eric Lippert的[GetHashCode准则和规则](http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for- gethashcode.aspx)特别是规则* GetHashCode返回的整数必须永远不会更改,而对象包含在依赖于哈希码保持稳定*的数据结构中。 – 2012-08-07 15:12:47
我首先想到这是一个很好的问题,现在我觉得我问了一些非常愚蠢的东西:)一段时间后,这一切都有意义,它刚开始时感觉不符合直觉。 '我以前从未使用HashSet'是我能想出的最佳借口:D谢谢你。 – 2012-08-07 15:26:44