IEquatable interface, what to do when checking for null

I implemented the IEquatable interface in the class with the following code.

public bool Equals(ClauseBE other) { if (this._id == other._id) { return true; } return false; } public override bool Equals(Object obj) { if (obj == null) { return base.Equals(obj); } if (!(obj is ClauseBE)) { throw new InvalidCastException("The 'obj' argument is not a ClauseBE object."); } return Equals(obj as ClauseBE); } public override int GetHashCode() { return this._id.GetHashCode(); } public static bool operator ==(ClauseBE a, ClauseBE b) { // cast to object so we call the overloaded Equals function which appropriately checks when b is null. return a.Equals(b as object); } public static bool operator !=(ClauseBE a, ClauseBE b) { // cast to object so we call the overloaded Equals function which appropriately checks when b is null. return !a.Equals(b as object); } 

This code works very well for most cases. However, the following check throws an exception in the method of overloading the equality operator, since a is null and, therefore, does not have the Equals method.

 if(this.Clause != null) { } 

What is the standard way to solve this problem?

EDIT

I went for it, but it looks rather bulky. I was hoping there was a more elegant way to achieve this.

  public static bool operator ==(ClauseBE a, ClauseBE b) { if (a as object == null && b as object == null) { return true; } if ((a as object == null && b as object != null) || (b as object == null && a as object != null)) { return false; } // cast to object so we call the overloaded Equals function which appropriately checks when b is null. return a.Equals(b as object); } public static bool operator !=(ClauseBE a, ClauseBE b) { if (a as object == null && b as object == null) { return false; } if((a as object == null && b as object != null) || (b as object == null && a as object != null)) { return true; } // cast to object so we call the overloaded Equals function which appropriately checks when b is null. return !a.Equals(b as object); } 

Decision

Thanks to everyone. I have a lot of good advice from everyone, I really appreciate it. This is what I finally decided, it is much more elegant than where I started. All code is the same, with the exception of operator overloads.

 public static bool operator ==(ClauseBE a, ClauseBE b) { if (ReferenceEquals(a, null) && ReferenceEquals(b, null)) { return true; } if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { return false; } return a.Equals(b); } public static bool operator !=(ClauseBE a, ClauseBE b) { return !(a == b); } 
+6
c # iequatable
source share
8 answers

It has always been easier for me to write a static operator with zero processing and have an override of Equals to call an overloaded operator with "this" as one of the parameters.

From Recommendations on Overloading Equals () and Operator == (C # Programming Guide)

 //add this code to class ThreeDPoint as defined previously // public static bool operator ==(ThreeDPoint a, ThreeDPoint b) { // If both are null, or both are same instance, return true. if (System.Object.ReferenceEquals(a, b)) { return true; } // If one is null, but not both, return false. if (((object)a == null) || ((object)b == null)) { return false; } // Return true if the fields match: return ax == bx && ay == by && az == bz; } public static bool operator !=(ThreeDPoint a, ThreeDPoint b) { return !(a == b); } 
+5
source share

This is how ReSharper creates equality operators and implements IEquatable<T> , which, I'm sure blindly ,-)

 public class ClauseBE : IEquatable<ClauseBE> { private int _id; public bool Equals(ClauseBE other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return other._id == this._id; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof(ClauseBE)) return false; return Equals((ClauseBE)obj); } public override int GetHashCode() { return this._id.GetHashCode(); } public static bool operator ==(ClauseBE left, ClauseBE right) { return Equals(left, right); } public static bool operator !=(ClauseBE left, ClauseBE right) { return !Equals(left, right); } } 
+2
source share

Check the null value and return false. Equalities must always be false if one of the operands is zero;

+1
source share

I think this is a little less cumbersome than dropping an Object before checking for null:

 ReferenceEquals(a, null) 
+1
source share

Other answers provide good solutions to a common problem.

However, your own code can be simplified into a relatively simple solution ...

First, at the beginning of your == statement, you have the following:

  // First test if (a as object == null && b as object == null) { return true; } 

This means that it’s too hard to work.

If ClauseBE is a reference type, you only need to compare with null - " as object " is redundant; equally, if ClauseBE is a value type, then it can never be null .

Assuming that ClauseBE is a reference type (the most likely case), then you can simplify this: note that we use Object.Equals() to avoid endless recursion and stack ejection.

  // First test if (Object.Equals(a, null) && Object.Equals(b, null)) { return true; } 

One useful shortcut is using Object.ReferenceEquals() - which handles zeros for you.

So you could write this instead:

  // First test if (Object.ReferenceEquals(a, b)) { return true; } 

with the bonus that it also handles the case where a and b are the same exact object.

Once you pass the Object.ReferenceEquals() test, you know that a and b are different.

So your next test:

  // Second test if ((a as object == null && b as object != null) || (b as object == null && a as object != null)) { return false; } 

can be simplified since you know that if a is null, b cannot be null, etc.

  // Second test if (Object.Equals(a, null) || Object.Equals(b, null)) { return false; } 

If this test fails, you know that a and b different, and that none of them are equal to zero. A good time to call your overridden Equals() .

  // Use the implementation of Equals() for the rest return a.Equals(b as object); 
+1
source share
 public class Foo : IEquatable<Foo> { public Int32 Id { get; set; } public override Int32 GetHashCode() { return this.Id.GetHashCode(); } public override Boolean Equals(Object obj) { return !Object.ReferenceEquals(obj as Foo, null) && (this.Id == ((Foo)obj).Id); // Alternative casting to Object to use == operator. return ((Object)(obj as Foo) != null) && (this.Id == ((Foo)obj).Id); } public static Boolean operator ==(Foo a, Foo b) { return Object.Equals(a, b); } public static Boolean operator !=(Foo a, Foo b) { return !Object.Equals(a, b); } public Boolean Equals(Foo other) { return Object.Equals(this, other); } } 
0
source share

I used the following approach, and it seemed to me that it worked well. Infact, Resharper offers this approach.

 public bool Equals(Foo pFoo) { if (pFoo == null) return false; return (pFoo.Id == Id); } public override bool Equals(object obj) { if (ReferenceEquals(obj, this)) return true; return Equals(obj as Foo); } 
0
source share

I prefer to execute all the comparison logic in the Equals (T) method and leave "if it is null, else ..." in the operator overloads in the framework.

The only tricky thing about overriding operator overloads is that you can no longer use these operators in your Equals implementation, for example, to compare with null . Instead, object.ReferenceEquals can be used to achieve the same effect.

Following the TwoDPoint example in the MSDN Guidelines for Overriding Equals () and Operator == , this is the template that I generate when implementing the value for the types:

 public override bool Equals( object obj ) { // Note: For value types, would use: // return obj is TwoDPoint && this.Equals( (TwoDPoint)obj ); return this.Equals( obj as TwoDPoint ); } public bool Equals( TwoDPoint other ) { // Note: null check not needed for value types. return !object.ReferenceEquals( other, null ) && EqualityComparer<int>.Default.Equals( this.X, other.X ) && EqualityComparer<int>.Default.Equals( this.Y, other.Y ); } public static bool operator ==( TwoDPoint left, TwoDPoint right ) { // System.Collections.Generic.EqualityComparer<T> will perform the null checks // on the operands, and will call the Equals overload if necessary. return EqualityComparer<TwoDPoint>.Default.Equals( left, right ); } public static bool operator !=( TwoDPoint left, TwoDPoint right ) { return !EqualityComparer<TwoDPoint>.Default.Equals( left, right ); } 

The form above is the safest implementation because it simply redirects field equality checks to the structure and does not require knowing if the equality operators overflow the fields. This is great to simplify this when you know that overload exists:

 public bool Equals( TwoDPoint other ) { return !object.ReferenceEquals( other, null ) && this.X == other.X && this.Y == other.Y; } 

You can also replace calls to EqualityComparer<T> in operational overloads with calls to static object.Equals when comparing link types or when box types do not matter:

 public static bool operator ==( TwoDPoint left, TwoDPoint right ) { return object.Equals( left, right ); } public static bool operator !=( TwoDPoint left, TwoDPoint right ) { return !object.Equals( left, right ); } 

See also. What is the best algorithm for an overridden GetHashCode? to implement GetHashCode .

0
source share

All Articles