HashSet 项可以更改为 Set 中的相同项
HashSet item can be changed into same item in Set
我有一个 节点 class :
public class Node : INode
{
public object Value { get; set; }
}
我有 EqualityComparer 这个节点 class 像这样:
public class INodeEqualityComparer : EqualityComparer<INode>
{
private INodeEqualityComparer()
{
}
private static readonly INodeEqualityComparer _instance =
new INodeEqualityComparer();
public static INodeEqualityComparer Instance
{
get { return _instance; }
}
public override bool Equals(INode x, INode y)
{
return (int)(x.Value) == (int)(y.Value);
}
public override int GetHashCode(INode obj)
{
return ((int)(obj.Value)).GetHashCode();
}
}
我通过传递 NodeEqualityComparer 创建我的 HashSet。
我有 4 个节点实例:
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(1);
当我将 n1,n2,n3,n4 添加到我的哈希集时,n4 会被忽略。
HashSet<INode> nodes = new HashSet<INode>(INodeEqualityComparer.Instance);
nodes.Add(n1);
nodes.Add(n2);
nodes.Add(n3);
nodes.Add(n4);
BUT 在我使用此更改后:
nodes.Where(n => (int)(n.Value) == 3).FirstOrDefault().Value = 1;
根据 NodeEqualityComparer,将有 2 个元素(值=1)相等。那些是 n1 和 n3。
为什么哈希集不会阻止更新节点或删除它?
这是设计使然:散列集合(无论是字典、散列集还是任何其他)假设对象的散列码在插入集合后不会改变。并且由于两个被认为相等的对象也必须具有相同的哈希码,因此这也意味着无论其 Equals
实现如何 returns 都不能因相同的参数而改变。
这适用于散列的内容:在字典中,这是关键。在集合中,这是整个对象。
In general, for mutable reference types, you should override GetHashCode() only if:
You can compute the hash code from fields that are not mutable; or
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
在您的 Node
class 中,您使用可变的 属性 (Value
) 来计算哈希码。这通常是个坏主意,实际上 ReSharper 会发出警告。再者,覆盖 Equals
和 GetHashCode
通常意味着您将类型视为 "value" 而不是 "entity",并且值应尽可能视为不可变的。
如果不能使对象不可变,请不要将其存储在哈希集合中。
我有一个 节点 class :
public class Node : INode
{
public object Value { get; set; }
}
我有 EqualityComparer 这个节点 class 像这样:
public class INodeEqualityComparer : EqualityComparer<INode>
{
private INodeEqualityComparer()
{
}
private static readonly INodeEqualityComparer _instance =
new INodeEqualityComparer();
public static INodeEqualityComparer Instance
{
get { return _instance; }
}
public override bool Equals(INode x, INode y)
{
return (int)(x.Value) == (int)(y.Value);
}
public override int GetHashCode(INode obj)
{
return ((int)(obj.Value)).GetHashCode();
}
}
我通过传递 NodeEqualityComparer 创建我的 HashSet。
我有 4 个节点实例:
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(1);
当我将 n1,n2,n3,n4 添加到我的哈希集时,n4 会被忽略。
HashSet<INode> nodes = new HashSet<INode>(INodeEqualityComparer.Instance);
nodes.Add(n1);
nodes.Add(n2);
nodes.Add(n3);
nodes.Add(n4);
BUT 在我使用此更改后:
nodes.Where(n => (int)(n.Value) == 3).FirstOrDefault().Value = 1;
根据 NodeEqualityComparer,将有 2 个元素(值=1)相等。那些是 n1 和 n3。
为什么哈希集不会阻止更新节点或删除它?
这是设计使然:散列集合(无论是字典、散列集还是任何其他)假设对象的散列码在插入集合后不会改变。并且由于两个被认为相等的对象也必须具有相同的哈希码,因此这也意味着无论其 Equals
实现如何 returns 都不能因相同的参数而改变。
这适用于散列的内容:在字典中,这是关键。在集合中,这是整个对象。
In general, for mutable reference types, you should override GetHashCode() only if:
You can compute the hash code from fields that are not mutable; or
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
在您的 Node
class 中,您使用可变的 属性 (Value
) 来计算哈希码。这通常是个坏主意,实际上 ReSharper 会发出警告。再者,覆盖 Equals
和 GetHashCode
通常意味着您将类型视为 "value" 而不是 "entity",并且值应尽可能视为不可变的。
如果不能使对象不可变,请不要将其存储在哈希集合中。