2016-12-15 3 views
-1

У меня возникли проблемы с переопределением метода GetHashCode() и метода Equals().Переопределение GetHash() и Equals()

public class Coordinate 
{ 
    int x; 
    int y; 

    public Coordinate(int p,int q)  
    { 
     this.x = p ; 
     this.y = q; 
    } 
} 

Предположим, что я создал два объекта координатной точки с одинаковыми координатами x и y.

Я хочу, чтобы моя программа поняла, что они равны.

Coordinate Point 1 = new Coordinate(0,0); 

Coordinate Point 2 = new Coordinate(0,0); 

По умолчанию они дают разные GetHashCode(), как и ожидалось. Я хочу, чтобы они выдавали один и тот же хэш-код, переопределяя его, а затем используя этот хэш-код в качестве ключа для генерации значений из Словаря. После поиска об этом я знаю, что мне также нужно переопределить Equals().

+0

Вы не задать вопрос. Вы хотите, чтобы мы объяснили разницу между различными методами в вашем последнем предложении? – Amy

+0

Итак, какие проблемы у вас были, переопределяя эти два метода? – Servy

+0

Возможно, вы можете посмотреть здесь: http://stackoverflow.com/questions/3103308/overridding-equals-and-gethash?rq=1 –

ответ

0

Вы должны переопределить Equals(), потому что, если два объекта имеют одинаковый хэш-код, это не значит, что они должны считаться равными. Хэш-код просто действует как «индекс», чтобы ускорить поиск.

Каждый раз, когда вы используете new, создается экземпляр, и он не будет тем же экземпляром, что и другой экземпляр. Это то, что делают ReferenceEquals() чеки - представьте две идентичные бутылки соды - они такие же, но они не то же самое bottle.

предназначено для проверки того, является ли вы (разработчик) хотите считать два экземпляра равными, даже если они не совпадают с экземпляром.

0

Вы можете реализовать что-то в этом духе:

public override bool Equal(Object o) { 
    if (object.ReferenceEquals(o, this)) 
    return true; 

    Coordinate other = o as Coordinate; 

    else if (null == other) 
    return false; 

    return x == other.x && y == other.y; 
} 

public override int GetHashCode() { 
    return x.GetHashCode()^y.GetHashCode(); 
} 

где Equals возвращение true, если и только если экземпляры равны в то время как GetHashCode() делает быстрой оценки (экземпляры не равны, если они имеют разный хэш-код, обратное, однако, неверно) и обеспечивает равномерное распределение хэшей, насколько это возможно (так что в Dictionary и аналогичных структурах мы имеем примерно одинаковое количество значений на каждый ключ)

https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx

https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx

0

Я бы переопределить названные методы, как это. Для метода GetHashCode я взял один из нескольких вариантов от this question, но вы можете выбрать другой, если хотите.

Я также изменил класс на неизменный. Вы должны использовать неизменяемые свойства/поля для вычисления хэш-кода.

public class Coordinate { 
    public Coordinate(int p, int q) { 
     x = p; 
     y = q; 
    } 

    private readonly int x; 
    private readonly int y; 

    public int X { get { return x; } } 
    public int Y { get { return y; } } 

    public override int GetHashCode() { 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = (int) 2166136261; 
      // Suitable nullity checks etc, of course :) 
      hash = (hash * 16777619)^x.GetHashCode(); 
      hash = (hash * 16777619)^y.GetHashCode(); 
      return hash; 
     }  
    } 

    public override bool Equals(object obj) { 
     if (obj == null) 
      return false; 

     var otherCoordinate = obj as Coordinate; 
     if (otherCoordinate == null) 
      return false; 

     return 
      this.X == otherCoordinate.X && 
      this.Y == otherCoordinate.Y;   
    } 
} 
+0

Downvoter, не могли бы вы прокомментировать? – Maarten

+0

Наконец-то удалось добиться того, что я пытался. Большое вам спасибо, сэр. Я очень рад, что вы взяли тайм-аут, чтобы дать этот аккуратный ответ. Не только вы, но и все остальные. Я был очень разочарован вчера, когда я написал этот вопрос. Люди отказались от голосования и обвинили меня в «возможном дублировании». Но, наконец, счастлив. Еще раз спасибо. – Avan

0

Что вы пытаетесь сделать, как правило, происходит, когда у вас есть неизменные объекты и такие, в любом случае, если вы не хотите использовать struct, вы можете сделать это следующим образом:

public class Coord : IEquatable<Coord> 
    { 
     public Coord(int x, int y) 
     { 
      this.X = x; 
      this.Y = y; 
     } 

     public int X { get; } 
     public int Y { get; } 
     public override int GetHashCode() 
     { 
      object.Equals("a", "b"); 
      // Just pick numbers that are prime between them 
      int hash = 17; 
      hash = hash * 23 + this.X.GetHashCode(); 
      hash = hash * 23 + this.Y.GetHashCode(); 
      return hash; 
     } 

     public override bool Equals(object obj) 
     { 
      var casted = obj as Coord; 
      if (object.ReferenceEquals(this, casted)) 
      { 
       return true; 
      } 
      return this.Equals(casted); 
     } 

     public static bool operator !=(Coord first, Coord second) 
     { 
      return !(first == second); 
     } 

     public static bool operator ==(Coord first, Coord second) 
     { 
      if (object.ReferenceEquals(second, null)) 
      { 
       if (object.ReferenceEquals(first, null)) 
       { 
        return true; 
       } 
       return false; 
      } 
      return first.Equals(second); 
     } 

     public bool Equals(Coord other) 
     { 
      if (object.ReferenceEquals(other, null)) 
      { 
       return false; 
      } 
      return object.ReferenceEquals(this, other) || (this.X.Equals(other.X) && this.Y.Equals(other.Y)); 
     } 
    } 

Примечание. Вы действительно должны сделать ваш класс неизменным, если вы выполняете обычное равенство, так как он может сломать ваш код, если вы используете коллекцию, основанную на хэше.

Я считаю, что хорошей практикой является выполнение всех этих перегрузок, когда вы хотите, чтобы вы выполняли обычную проверку равенства. Тем более, что, когда object.GetHashCode() возвращает одно и то же значение для двух объектов, Dictionary и другие коллекции, основанные на хеше, используют оператор равенства по умолчанию, который использует object.Equals.

Object.ReferenceEquals(Ob,Ob) определить ссылочное равенство, a.k.a, если обе контрольные точки относятся к одному и тому же распределенному значению, причем две ссылки равны, гарантируя, что это тот же самый объект.

Object.Equals(Ob) является виртуальным методом в object классе, по умолчанию он сравнивает ссылки так же, как Object.ReferenceEquals(Ob,Ob)

Object.Equals(Ob,Ob) называет Ob.Equals(Ob), так что да, проверяя только статическая стенографию для нуля заранее IIRC.

+0

Спасибо. Сэр. – Avan

0

Вот простой способ сделать это.

Во-первых, переопределить ToString() метод вашего класса что-то вроде этого:

public override string ToString() 
{ 
    return string.Format("[{0}, {1}]", this.x, this.y); 
} 

Теперь вы можете легко переопределить GetHashCode() и Equals() вроде этого:

public override int GetHashCode() 
{ 
    return this.ToString().GetHashCode(); 
} 

public override bool Equals(object obj) 
{ 
    return obj.ToString() == this.ToString(); 
} 

Теперь, если вы попытаетесь это сделать:

Coordinate p1 = new Coordinate(5, 0); 
Coordinate p2 = new Coordinate(5, 0); 

Console.WriteLine(p1.Equals(p2)); 

вы Добьетесь:

Правда

+0

Вы используете результат вызова '.ToString()' для реализации как 'GetHashCode', так и' Equals'. Для меня это выглядит довольно неэффективно, поскольку у вас есть доступ к значениям «x» и «y». – Maarten

Смежные вопросы