C#这是实现GetHashCode的一种不好的方法吗?

时间:2013-10-07 19:52:48

标签: c# gethashcode

我正在尝试为我已覆盖Equals的对象实现GetHashCode。

public override bool Equals(object obj)
{
    var myobject = obj as MyObject;
    if (myobject == null)
        return false;

    if (myobject.SomeProperty == null || SomeProperty == null)
        return false;

    // All default SomeProperty's are equal
    if (myobject.SomeProperty.IsDefault)
        return SomeProperty.IsDefault;

    // Otherwise equality is based on ID
    return myobject.SomeProperty.ID == SomeProperty.ID;
}

public override int GetHashCode()
{
    if (SomeProperty != null && SomeProperty.IsDefault)
        return 0;
    else return base.GetHashCode();
}

这是一种合理的方法吗,还是可能导致与base.GetHashCode()冲突?

编辑:我很欣赏迄今为止给出的解决方案,但仍然存在同样的问题。如果我没有实现一个完整的GetHashCode并依赖于其他一些实现,无论是base.GetHashCode()还是Guid.GetHashCode(),是否有可能与硬编码的0值发生哈希码冲突?如果是这样,有没有一种简单的方法可以避免它?

2 个答案:

答案 0 :(得分:3)

根据您的Equals方法,您认为真正属于对象的“身份”的是SomeProperty.ID的值,还有一些额外的空值/属性等处理。

这也应该反映在哈希码中。

您应该像处理Equals方法一样开始处理所有这些边缘情况。看起来好像你走了这条道路,但并没有完全达到目的。如果对象的SomeProperty为空IsDefault则它没有ID,对我们来说,所有这些对象都是“相同的”并且应该具有相同的哈希码。

之后,不是利用基类的哈希码,而是需要在ID属性上实际建立哈希,这就是Equals方法接下来要做的事情。由于IDGuid我们知道它有一个明智的GetHashCode实现,所以我们可以利用它,然后你就完成了:

public override int GetHashCode()
{
    if (SomeProperty == null || SomeProperty.IsDefault)
        return 0;
    else 
        return SomeProperty.ID.GetHashCode();
}

或者,如果您更容易阅读,我们可以颠倒逻辑。而不是说,“如果这没有ID,则返回零,否则返回ID的哈希码”我们可以说,“如果我们有一个ID,则返回它的哈希码,否则只返回零:

public override int GetHashCode()
{
    if (SomeProperty != null && !SomeProperty.IsDefault)
        return SomeProperty.ID.GetHashCode();
    else 
        return 0;
}

我个人认为第一种方法与Equals方法相比更加对称,但第二种方法似乎更接近你想要做的事情,这就是为什么我把它扔到那里。

答案 1 :(得分:1)

这不是一个好的解决方案。 documentation显示

  

哈希函数必须具有以下属性:

     

如果两个对象比较相等,则每个对象的GetHashCode方法   对象必须返回相同的值。但是,如果两个对象没有   比较相同,两个对象的GetHashCode方法不相同   必须返回不同的值。

     

对象的GetHashCode方法必须始终返回相同的值   哈希码只要没有对象状态的修改即可   确定对象的Equals方法的返回值。注意   这仅适用于当前执行的应用程序,并且   如果运行应用程序,则可以返回不同的哈希代码   试。

     

为获得最佳性能,哈希函数必须生成随机数   所有输入的分配。

对于许多不相等的对象,您可能会返回0,尽管这不会破坏租户“如果两个对象不相等,则两个对象的GetHashCode方法不必返回不同的值”如果太多对象返回0然后你将不会满足“为了获得最佳性能,哈希函数必须为所有输入生成随机分布。”

此外,

  

覆盖GetHashCode的派生类也必须覆盖等于   保证两个被认为相等的对象具有相同的哈希码;   否则,Hashtable类型可能无法正常工作。

因此,您也应该发布Equals的实现,以确保GetHashCode有效。

我建议将其更新为

public override int GetHashCode()
{
    if (SomeProperty == null || SomeProperty.IsDefault)
        return base.GetHashCode() ;
    else return SomeProperty.ID.GetHashCode();
}

此外,有关GetHashCode实现的详细讨论,您可以查看此post

此外,如果您要返回SomeProperty==null的两个对象中的false,那么您的等号是否有意?

或者你的意思是

if (myobject.SomeProperty == null && SomeProperty == null)
    return true;
if (myobject.SomeProperty == null || SomeProperty == null)
    return false;