-1

I am having trouble overriding the GetHashCode() method and the Equals() method.

public class Coordinate
{ 
   int x; 
   int y;

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

Suppose I created two Coordinate point objects with same x and y coordinates .

I want my program to understand that they are equal.

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

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

By default they are giving different GetHashCode() as expected. I want them to give same hash code by overriding it and then use that hash code as a Key to generate values from a Dictionary. After searching about it, I know that I also have to override Equals().

Servy
  • 202,030
  • 26
  • 332
  • 449
Avan
  • 366
  • 3
  • 17
  • You didn't ask a question. You want us to explain the difference between the different methods in your last sentence? –  Dec 15 '16 at 14:27
  • So what problems did you have overriding these two methods? – Servy Dec 15 '16 at 14:29
  • You may have a look here: http://stackoverflow.com/questions/3103308/overridding-equals-and-gethash?rq=1 – Amittai Shapira Dec 15 '16 at 14:34
  • Should I implement Equals(ob^, ob^) through IEqualityComparer interface or just override the Object.Equals(ob) method . or both .? – Avan Dec 15 '16 at 14:35
  • @Servy are you using a tool to edit questions? Your edit changed all "hashcode" to "has code", and I doubt that was your intention – C.Evenhuis Dec 15 '16 at 14:41
  • Possible duplicate of [What's the best strategy for Equals and GetHashCode?](http://stackoverflow.com/questions/2363143/whats-the-best-strategy-for-equals-and-gethashcode) – Liam Dec 15 '16 at 14:54
  • @C.Evenhuis It was just a simple typo. Why did you roll back the question and introduce a ton of errors that had been fixed? – Servy Dec 15 '16 at 15:54
  • @Servy you removed the only bit the OP expressed his doubts about (the essence of the question) and changed perfectly fine "hashcode" into "has code" twice (a typo?) - making it an invalid edit in my point of view. The errors fixed by others were the ones you introduced - except the title which I then corrected again. – C.Evenhuis Dec 15 '16 at 18:04
  • @C.Evenhuis I changed HashCode to has code, because it's two words, not one, and shouldn't be capitalized. Yes, I was typing too fast and apparently didn't press a key hard enough; had you fixed it, that would have been helpful. I also changed more than just that one word (twice), so why you reverted everything else makes no sense. I also remove the second question that the OP tacked on to the end of his actual question, because it's not appropriate to ask multiple entirely separate, questions in a single question. You should be asking a single question per question. – Servy Dec 15 '16 at 18:44
  • @Servy I agree with the last bit, I just felt more that the part you didn't erase was his introduction or "background" and the part you did was the actual question - but without an clearly specified question it's just a difference of opinion. I won't be so quick in reverting edits the next time, sorry for wasting some of your time. – C.Evenhuis Dec 15 '16 at 21:31

5 Answers5

0

You have to override Equals(), because if two objects have the same hashcode, it doesn't mean they are to be considered equal. The hashcode simply acts as an "index" to speed up searches.

Every time you use new, an instance is created and it will not be the same instance as another instance. This is what ReferenceEquals() checks - imagine two identical bottles of soda - they're the same, but they're not the same bottle.

Equals() is meant to check whether you (the developer) want to consider two instances as equal, even though they are not the same instance.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
0

You can implement something in this vein:

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

where Equals return true if and only if instances are equal while GetHashCode() does a quick estimation (instances are not equal if they have different hash code, the reverse, however, is not true) and ensures uniform distribution of the hashes as far as it's possible (so that in Dictionary and alike structures we have roughly equally number of values per each key)

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

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
0

I would override the named methods like this. For the GetHashCode method I took one of several options from this question, but you can choose another if you like.

I also changed the class to immutable. You should only use immutable properties/fields to calculate the hashcode.

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;        
    }
 }
Community
  • 1
  • 1
Maarten
  • 22,527
  • 3
  • 47
  • 68
  • Finally could able to achieve what I was trying to. Thank you so much, Sir. I am very happy that you took time out to give this neat reply . Not just you but all others here. I was very disappointed yesterday when I wrote this question. People were down voting it and accusing me "possible duplicate". But finally happy now. Thank you again. – Avan Dec 16 '16 at 12:11
0

What you try to do typically happens when you have immutable objects and such, anyway if you don't want to use a struct, you can do it like this :

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

Note . You really should make your class immutable if you do custom equality since it could break your code if you use a hash based collection.

I think it is considered good practice to do all those overloads when you want custom equality checking like you do. Especially since when object.GetHashCode() returns the same value for two object, Dictionary and other hash based collections use the default equality operator which uses object.Equals.

Object.ReferenceEquals(Ob,Ob) determine reference equality, a.k.a if both reference point to the same allocated value, two references being equal ensure you it's the exact same object.

Object.Equals(Ob) is the virtual method in object class, by default it compares references just like Object.ReferenceEquals(Ob,Ob)

Object.Equals(Ob,Ob) calls the Ob.Equals(Ob), so yeah just a static shorthand checking for null beforehand IIRC.

Uwy
  • 457
  • 7
  • 13
0

Here's a simple way you to do it.

First, override the ToString() method of your class to something like this:

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

Now you can easily override GetHashCode() and Equals() like this:

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

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

Now if you try this:

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

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

you'll get:

True

Kidus
  • 1,785
  • 2
  • 20
  • 36
  • You are using the result of the `.ToString()` call to implement both `GetHashCode` and `Equals`. It seems fairly inefficient to me, since you have access to both `x` and `y` values. – Maarten Dec 15 '16 at 14:56