首页 文章

如何使用覆盖的逻辑Equals()实现GetHashCode()的覆盖

提问于
浏览
3

我有一些类如下,我已经为几乎所有的类实现了 Equals(Object) 方法 . 但我不知道怎么写 GetHashCode() . 到目前为止,我在 Dictionary 集合中使用这些数据类型作为值类型,我想我应该覆盖 GetHashCode() .

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

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

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;
    }
}

EDIT: 我收到此警告:

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

2 回答

  • 8

    首先,正如我认为您理解的那样,无论您在何处实施 Equals ,您还必须实施 GetHashCode . GetHashCode 的实现必须反映 Equals 实现的行为,但通常不会使用它 .

    http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx - 特别是"Notes to Implementers"

    因此,如果您以 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) ...
    
  • 12

    我更喜欢乔什布洛赫的方法 .

    这是 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用于哈希码计算的属性也应该是不可变的 .

相关问题