112

I've already gone through question

I understand that, it is necessary to implement ==, != and Equals().

public class BOX { double height, length, breadth; // this is first one '==' public static bool operator== (BOX obj1, BOX obj2) { return (obj1.length == obj2.length && obj1.breadth == obj2.breadth && obj1.height == obj2.height); } // this is second one '!=' public static bool operator!= (BOX obj1, BOX obj2) { return !(obj1.length == obj2.length && obj1.breadth == obj2.breadth && obj1.height == obj2.height); } // this is third one 'Equals' public override bool Equals(BOX obj) { return (length == obj.length && breadth == obj.breadth && height == obj.height); } } 

I assume, I've written code properly to override ==,!=,Equals operators. Though, I get compilation errors as follows.

'myNameSpace.BOX.Equals(myNameSpace.BOX)' is marked as an override but no suitable method found to override. 

So, question is - How to override above operators & get rid of this error?

2
  • isn't the signature for Equals like public override bool Equals(object o)? Commented Aug 23, 2014 at 11:53
  • 2
    Resharper suggests writing != like return !(obj1 == obj2) which should take advantage of what you already wrote for the == overload. Commented Jul 18, 2017 at 19:44

4 Answers 4

125

As Selman22 said, you are overriding the default object.Equals method, which accepts an object obj and not a safe compile time type.

In order for that to happen, make your type implement IEquatable<Box>:

public class Box : IEquatable<Box> { double height, length, breadth; public static bool operator ==(Box obj1, Box obj2) { if (ReferenceEquals(obj1, obj2)) return true; if (ReferenceEquals(obj1, null)) return false; if (ReferenceEquals(obj2, null)) return false; return obj1.Equals(obj2); } public static bool operator !=(Box obj1, Box obj2) => !(obj1 == obj2); public bool Equals(Box other) { if (ReferenceEquals(other, null)) return false; if (ReferenceEquals(this, other)) return true; return height.Equals(other.height) && length.Equals(other.length) && breadth.Equals(other.breadth); } public override bool Equals(object obj) => Equals(obj as Box); public override int GetHashCode() { unchecked { int hashCode = height.GetHashCode(); hashCode = (hashCode * 397) ^ length.GetHashCode(); hashCode = (hashCode * 397) ^ breadth.GetHashCode(); return hashCode; } } } 

Another thing to note is that you are making a floating point comparison using the equality operator and you might experience a loss of precision.

Sign up to request clarification or add additional context in comments.

3 Comments

public override bool Equals(object obj) => obj is Box && Equals(obj as Box);
use: public override int GetHashCode() => Hashcode.Combine(height, length, breadth); instead of the "unchecked" section to simplify the code
Regarding the note about the "loss of precision": If you decide to implement a fuzzy Equals which accounts for loss of precision and declares two boxes to be equal with regards to a certain epsilon, you will violate the GetHashCode contract: GetHashCode should never return different results for objects that are "Equal".
51

I think you declared the Equals method like this:

public override bool Equals(BOX obj) 

Since the object.Equals method takes an object, there is no method to override with this signature. You have to override it like this:

public override bool Equals(object obj) 

If you want type-safe Equals, you can implement IEquatable<BOX>.

Comments

45

In fact, this is a "how to" subject. So, here is the reference implementation:

 public class BOX { double height, length, breadth; public static bool operator == (BOX b1, BOX b2) { if ((object)b1 == null) return (object)b2 == null; return b1.Equals(b2); } public static bool operator != (BOX b1, BOX b2) { return !(b1 == b2); } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) return false; var b2 = (BOX)obj; return (length == b2.length && breadth == b2.breadth && height == b2.height); } public override int GetHashCode() { return height.GetHashCode() ^ length.GetHashCode() ^ breadth.GetHashCode(); } } 

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

UPDATE: the cast to (object) in the operator == implementation is important, otherwise, it would re-execute the operator == overload, leading to a stackoverflow. Credits to @grek40.

This (object) cast trick is from Microsoft String == implementaiton. SRC: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs#L643

6 Comments

Don't write if (null == b1), it will re-execute the operator == overload, leading to a stackoverflow. Same for b2.
@grek40 , will if ((object)b1==null) avoid the issue?
Yes, this should do the trick. Alternative would be using object.ReferenceEquals like the other answer.
For HashCode generation, it is better to use a tupple.GetHashCode(): (height, length, breadth).GetHashCode(). The problem with using XOR is that height, length, breadth probably use only the lower bits and the higher bits are unused. A hash ideally uses all 32 bits of the integer. This is achieved by bit-shifting the parameters by different values, which GetHashCode() does.
|
8
public class BOX { double height, length, breadth; public static bool operator == (BOX b1, BOX b2) { if (b1 is null) return b2 is null; return b1.Equals(b2); } public static bool operator != (BOX b1, BOX b2) { return !(b1 == b2); } public override bool Equals(object obj) { if (obj == null) return false; return obj is BOX b2? (length == b2.length && breadth == b2.breadth && height == b2.height): false; } public override int GetHashCode() { return (height,length,breadth).GetHashCode(); } } 

1 Comment

using is instead of == eliminates the workaround of casting to object

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.