[英]implement GetHashCode() for objects that contain collections
考虑以下对象:
class Route
{
public int Origin { get; set; }
public int Destination { get; set; }
}
Route实现了相等运算符。
class Routing
{
public List<Route> Paths { get; set; }
}
我使用下面的代码为Routing对象实现GetHashCode方法,它似乎工作,但我想知道这是否是正确的方法呢? 我依靠平等检查,因为我不确定我以为我会问你们。 我可以只是总结哈希码还是我需要做更多的魔法以保证所需的效果?
public override int GetHashCode() =>
{
return (Paths != null
? (Paths.Select(p => p.GetHashCode())
.Sum())
: 0);
}
我在这里检查了几个GetHashCode()
问题,以及MSDN和Eric Lippert关于这个主题的文章,但是找不到我想要的东西。
我认为您的解决方案很好。 (后来很多评论:LINQ的Sum
方法将在checked
上下文中起作用,因此你可以很容易地得到一个OverflowException
,这意味着它毕竟不是那么好。)但是更常见的是做XOR(不带进位的加法)。 所以它可能是这样的
public override int GetHashCode()
{
int hc = 0;
if (Paths != null)
foreach (var p in Paths)
hc ^= p.GetHashCode();
return hc;
}
附录(接受答复后):
请记住,如果您在Dictionary<Routing, Whatever>
, HashSet<Routing>
或使用哈希表的其他情况下使用此类型Routing
,那么如果有人在Routing
后更改(变更) Routing
,则您的实例将丢失已添加到集合中。
如果您确定永远不会发生,请使用上面的代码。 如果确保没有人改变引用的Routing
, Dictionary<,>
等仍然有效。
另一个选择就是写
public override int GetHashCode()
{
return 0;
}
如果您认为永远不会使用哈希码。 如果每个instace都为哈希代码返回0
,那么使用哈希表会得到非常糟糕的性能,但是你的对象不会丢失。 第三种选择是抛出NotSupportedException
。
来自Jeppe Stig Nielsen的答案的代码可行,但它可能会导致大量重复哈希码值。 假设您正在哈希一个0-100范围内的整数列表,那么您的哈希码将被保证在0到255之间。这在字典中使用时会产生大量冲突。 这是一个改进版本:
public override int GetHashCode()
{
int hc = 0;
if (Paths != null)
foreach (var p in Paths) {
hc ^= p.GetHashCode();
hc = (hc << 7) | (hc >> (32 - 7)); //rotale hc to the left to swipe over all bits
}
return hc;
}
随着越来越多的项目被散列,此代码将至少涉及所有位。
作为指导原则,对象的哈希值必须与对象的整个生命周期相同。 我会单独留下GetHashCode
函数,而不是覆盖它。 仅当您要将对象放在哈希表中时才使用哈希码。
您应该阅读Eric Lippert关于.NET中哈希码的精彩文章: GetHashCode的指南和规则 。
引用该文章:
准则:GetHashCode返回的整数永远不会改变
规则:当对象包含在依赖于哈希代码保持稳定的数据结构中时,GetHashCode返回的整数必须永远不会更改
如果对象的哈希代码在哈希表中变异,那么显然Contains方法就会停止工作。 你把对象放在#5桶中,你改变它,当你问集合是否包含变异对象时,它会在#74桶中查找并找不到它。
您实现的GetHashCode
函数将不会在对象的生命周期内返回相同的哈希代码。 如果使用此函数,如果将这些对象添加到哈希表中,则会遇到麻烦: Contains
方法不起作用 。
我认为这不是一种正确的方法,因此必须确定最终的hashcode
它必须对指定的对象是唯一的。 在您的情况下,您执行Sum()
,它可以在集合中使用不同的哈希码生成相同的结果(在末尾哈希码只是整数)。
如果您的目的是根据集合的内容确定相等性,那么只需比较两个对象之间的这些切片。 顺便说一句,这可能是耗时的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.