What needs to be overridden in a struct to ensure equality operates properly?

C#.NetStructOperatorsEquals Operator

C# Problem Overview


As the title says: do I need to override the == operator? how about the .Equals() method? Anything I'm missing?

C# Solutions


Solution 1 - C#

An example from msdn

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
        return obj is Complex c && this == c;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}

Solution 2 - C#

You should also implement IEquatable<T>. Here is an excerpt from Framework Design Guidelines:

> DO implement IEquatable on value types. The Object.Equals method on value types causes boxing, and its default implementation is not very effcient because it uses refection. IEquatable.Equals can offer much better performance and can be implemented so that it does not cause boxing.

public struct Int32 : IEquatable<Int32> {
    public bool Equals(Int32 other){ ... }
}

> DO follow the same guidelines as for > overriding Object.Equals when > implementing IEquatable.Equals. > See section 8.7.1 for detailed > guidelines on overriding Object.Equals

Solution 3 - C#

Unfortunetely I don't have enough reputation to comment other entries. So I'm posting possible enhancement to the top solution here.

Correct me, if i'm wrong, but implementation mentioned above

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
      return obj is Complex && this == (Complex)obj;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}

Has major flaw. I'm refering to

  public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }

XORing is symmetrical, so Complex(2,1) and Complex(1,2) would give same hashCode.

We should probably make something more like:

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }

Solution 4 - C#

Most of the time you can avoid implementing Equals and GetHashcode in structs - because there is an automatic implementation by the compiler for Value types using bitwise content + reflection for reference members.

Have a look at that post : https://stackoverflow.com/questions/1951186/which-is-best-for-data-store-struct-classes/32797530#32797530

So for ease of use you could still implement == and !=.

But most of the time you can avoid implementing Equals and GetHashcode.
A case where you'd have to implement Equals and GetHashCode is for a field that you don't wan't to take into account.
For instance a field that varies as time goes by like Age of a Person or instantSpeed of a car( the identity of the object shouldn't change if you want to find it back in the dictionary at the same place)

Regards, best code

Solution 5 - C#

The basic difference among the two is that the == operator is static, i.e. the appropriate method to invoke is determined at compile time, while the Equals method is invoked dinamically on an instance.
Defining both is probably the best thing to do, even if this matters less in the case of structs, since structs cannot be extended (a struct can't inherit from another).

Solution 6 - C#

Just for completness I would also advice to overload Equals method:

public bool Equals(Complex other) 
{
   return other.re == re && other.im == im;
}

this is a real spead improvement as there is no boxing occuring of the input argument of Equals(Object obj) method

Some best prac­tices for using value types:

  • make them immutable
  • over­ride Equals (the one that takes an object as argument);
  • over­load Equals to take another instance of the same value type (e.g. * Equals(Complex other));
  • over­load oper­a­tors == and !=;
  • over­ride GetHashCode

This comes from this post: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRCIXView Question on Stackoverflow
Solution 1 - C#UpTheCreekView Answer on Stackoverflow
Solution 2 - C#Dzmitry HubaView Answer on Stackoverflow
Solution 3 - C#AjkView Answer on Stackoverflow
Solution 4 - C#Emmanuel DURINView Answer on Stackoverflow
Solution 5 - C#Paolo TedescoView Answer on Stackoverflow
Solution 6 - C#Tomasz JaskuλaView Answer on Stackoverflow