我有一些带有一堆字段的对象,我发现自己必须实现GetHashCode和Equals.手动遍历每个字段是痛苦的,所以我这样编写它们:
public override int GetHashCode()
{
int hash = 17;
foreach (PropertyInfo p in GetType().GetProperties())
{
hash = hash * 23 + p.GetValue(this, null).GetHashCode();
}
return hash;
}
public override bool Equals(object obj)
{
foreach (PropertyInfo p in GetType().GetProperties())
{
if (p.GetValue(obj, null) != p.GetValue(this, null))
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
除了速度考虑因素,为什么我不应该像这样实现它们?
以下是我避免这条路线的几个原因
.Equals.考虑两种不同的参考文献是非常可能和合法的,Equals并且会超过您的测试.GetHashCode方法忽略了属性null 下面是一个类型的具体示例,它将在您的应用程序中导致无限递归
class C1 {
public object Prop1 { get; set; }
};
var local = new C1();
local.Prop1 = local;
var x = local.GetHashCode(); // Infinite recursion
Run Code Online (Sandbox Code Playgroud)
任何值类型属性都将被GetValue调用装箱,这意味着即使它们具有相同的值,它们也永远不会相等.
您可以通过调用静态Equals(x,y)方法来避免这种情况- x.Equals(y)如果需要,它将遵循虚方法 - 而不是使用非虚拟==运算符,在这种情况下,它将始终测试引用相等性.
if (!object.Equals(p.GetValue(obj, null), p.GetValue(this, null)))
return false;
Run Code Online (Sandbox Code Playgroud)