Как реализовать переопределение GetHashCode () с логикой переопределения Equals () - PullRequest
3 голосов
/ 22 марта 2012

У меня есть несколько классов, как показано ниже, я реализовал метод Equals(Object) почти для всех из них. Но я не знаю, как написать GetHashCode(). Поскольку я использовал эти типы данных в качестве типа значения в коллекции Dictionary, я думаю, что я должен переопределить GetHashCode().

1.Я не знаю, как реализовать GetHashCode() с логикой Equals(Object).

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 ]

12 голосов
/ 22 марта 2012

Во-первых, как я думаю, вы понимаете, где бы вы ни внедрили Equals, вы ДОЛЖНЫ также реализовать GetHashCode.Реализация GetHashCode должна отражать поведение реализации Equals, но обычно не используется .

См. http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx - особенно "Примечания кРеализаторы "

Итак, если вы берете пример реализации Item Equals, вы рассматриваете оба значения id и name, чтобы повлиять на равенство.Таким образом, оба из них должны внести свой вклад в реализацию GetHashCode.

Пример того, как вы могли бы реализовать GetHashCode для Item, будет выглядеть следующим образом (обратите внимание, что вам может потребоваться сделать его эластичнымобнуляемое поле name:

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

См. сообщение Эрика Липперта в блоге о рекомендациях для 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) ...
8 голосов
/ 22 марта 2012

Я предпочитаю подход Джоша Блоха.

Вот пример для класса Param.

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

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

Также проверьте эту ссылку: .net - лучший алгоритм для GetHashCode Свойства, используемые для вычисления хеш-кода, также должны быть неизменяемыми.

...