【问题标题】:how to implement override of GetHashCode() with logic of overriden Equals()如何使用重写 Equals() 的逻辑实现 GetHashCode() 的重写
【发布时间】:2012-04-07 08:19:14
【问题描述】:

我有一些类如下,我已经为几乎所有类实现了Equals(Object) 方法。但我不知道如何写 GetHashCode() 。就我在Dictionary 集合中使用这些数据类型作为值类型而言,我认为我应该覆盖GetHashCode()

1.我不知道如何用Equals(Object)的逻辑实现GetHashCode()

2.有一些派生类,如果我为基类(Param)覆盖GetHashCode()Equals(Object),是否还需要为孩子覆盖它?

class Param
{
    ...
    public Int16 id { get; set; }
    public String name { get; set; }
    ...
    public override bool  Equals(object obj)
    {
        if ( obj is Param){
            Param p = (Param)(obj);
            if (id > 0 && p.id > 0)
                return (id == p.id);
            else if (name != String.Empty && p.name != String.Empty)
                return (name.equals(p.name));
            else
                return object.ReferenceEquals(this, obj);
        }
        return false;
    }
}  
class Item
{
    public int it_code { get; set; }
    public Dictionary<String, Param> paramAr { get; set; }
    ...
    public override bool Equals(Object obj)
    {
        Item im = new Item();
        if (obj is Item)
            im = (Item)obj;
        else 
            return false;

        if (this.it_code != String.Empty && im.it_code != String.Empty)
            if (this.it_code.Equals(im.it_code)) 
                return true;

        bool reParams = true;
        foreach ( KeyValuePair<String,Param> kvp in paramAr ){
            if (kvp.Value != im.paramAr[kvp.Key]) {
                reParams = false;
                break;
            }
        }
        return reParams;
    }
}
class Order
{

    public String or_code { get; set; }
    public List <Item> items { get; set; }
    ...
    public override bool Equals( Object obj ){
        Order o = new Order();
        if (obj is Order)
            o = (Order)obj;
        else
            return false;

        if (this.or_code != String.Empty && o.or_code != String.Empty)
            if (this.or_code.Equals(o.or_code))
                return true;
        bool flag = true;
        foreach( Item i in  items){
            if (!o.items.Contains(i)) { 
                flag = false;
                break;
            }
        }
        return flag;
    }
}

编辑: 我收到这个警告:

警告:'Item' 会覆盖 Object.Equals(object o) 但不会 覆盖 Object.GetHashCode()

【问题讨论】:

  • 我相信在编写GetHashCode 时您需要考虑的唯一因素是,当两个对象相等时(通过调用Equals),它们的哈希码也必须相等。相反,如果两个哈希码相等,这并不意味着对象本身是相等的(尽管它们可能是相等的)。每当您编写 EqualsGetHashCode 的自定义实现时,您都必须为其他方法编写一些内容,以确保我在上面解释的逻辑保持正确。
  • Visual Studio 现在可以帮助解决这个问题 docs.microsoft.com/en-us/visualstudio/ide/reference/…

标签: c# overriding gethashcode


【解决方案1】:

我更喜欢 Josh Bloch 的方法。

这是Param 类的示例。

override GetHashCode(object obj)
{
 unchecked
    {
        int hash = 17;

        hash = hash * 23 + id.GetHashCode();
        hash = hash * 23 + name.GetHashCode();
        return hash;
    }
}

另外,请查看此链接:.net - best algorithm for GetHashCode 用于哈希码计算的属性也应该是不可变的。

【讨论】:

    【解决方案2】:

    首先,我想你明白了,无论你在哪里实现Equals,你都必须同时实现GetHashCodeGetHashCode 的实现必须反映Equals 实现的行为,但它通常不使用它。

    参见http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx - 尤其是“实施者须知”

    因此,如果您以 EqualsItem 实现为例,您正在考虑 idname 的值来影响相等性。因此,这两者都必须有助于GetHashCode 的实现。

    如何为Item 实现GetHashCode 的示例如下所示(请注意,您可能需要使其适应可空的name 字段):

    public override GetHashCode()
    {
        return id.GetHashCode() ^ name.GetHashCode();
    }
    

    请参阅 Eric Lippert 的博客文章,了解 GetHashCode - http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/ 的指南

    至于您是否需要在子类中重新实现GetHashCode - 是的,如果您还覆盖Equals - 根据第一个(和主要)点 - 两者的实现必须一致 - 如果两个项目是Equals 认为相等,那么它们必须从 GetHashCode 返回相同的值。

    旁注: 作为代码的性能改进(避免多次强制转换):

    if ( obj is Param){
        Param p = (Param)(obj);
    
    Param p = obj as Param;
    if (p != null) ...
    

    【讨论】:

    • order 类呢,它只有一个 id 和一个列表,我不能使用其列表中的所有值来生成哈希码。
    • List 对象有一个GetHashCode 实现,这可能足以满足您的目的。因为列表会影响平等,所以您必须在 GetHashCode 实现中考虑它。但是,再次查看您的 Equals 实现,您在分层意义上使用它们 - 如果 id 匹配,则无论其名称值如何,对象都是相等的。所以GetHashCode 的实现需要与我最初的建议不同;我还没有弄清楚如何......(还)
    • @rene 如果这就是你在 Equals 中所做的,那么是的,这正是你需要做的。
    • @KAJ 列表的 GetHashCode 将基于列表的引用,而不是其内容。具有相同项目的两个不同列表不一定具有相同的哈希码。现在,如果您将 Orders 的相等性定义为仅基于订单代码而不是商品,那么这些问题就会消失。 Equals 可以只比较订单代码,而 getHashCode 可以只返回订单代码的哈希码。如果程序需要支持具有相同订单代码和不同项目的两个不同订单,则需要在 equals 和 GetHashCode 中使用列表中的每个项目。
    • @Servy:这就是我的想法(即将进行概念验证)。基本问题是,GetHashCode 应该被快速评估,因此迭代列表中的所有项目听起来不是一个好主意;但是,如果它是相等性测试的一部分,它必须被包括在内。
    猜你喜欢
    • 2011-08-16
    • 2019-02-02
    • 2016-04-21
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多