Tag Archives: Equality

C# : How to write a custom Equality Comparer to be used for a HashSet

I need to write a custom Equality Comparer to be used for a class that I created.

Class that will be used for the HashSet

 ///<summary>Item for HashSet example</summary>
public enum ItemGroup
{
    group1 = 1,
    group2,
    group3,
    group4
}
public class Item
{
    public string Name { get; set; }
    public ItemGroup Group { get; set; }

    public Item(string name, ItemGroup group)
    {
        Name = name;
        Group = group;
    }
}
///<summary>Custom Equality Comparer using the base class EqualityComparer<T></summary>
public class MyItemEqualityComparer : EqualityComparer<Item>
{
    //make this a singleton object
    private static readonly MyItemEqualityComparer _instance = new MyItemEqualityComparer();

    public static MyItemEqualityComparer Instance { get { return _instance; } }

    private MyItemEqualityComparer() { }

    public override bool Equals(Item x, Item y)
    {
        return x.Name.ToUpperInvariant() == y.Name.ToUpperInvariant() && x.Group == y.Group;
    }
    public override int GetHashCode(Item obj)
    {
        return obj.Name.ToUpperInvariant().GetHashCode() ^ obj.Group.GetHashCode();
    }
}

Using

class Program
{
    static void Main(string[] args)
    {
        var items = new HashSet<Item>(MyItemEqualityComparer.Instance);
        items.Add(new Item("Item 1", ItemGroup.group1));
        items.Add(new Item("Item 2", ItemGroup.group2));
        items.Add(new Item("ITEM 3", ItemGroup.group3));
        items.Add(new Item("ITEM 3", ItemGroup.group3));
        items.Add(new Item("Item 3", ItemGroup.group3));

        foreach (Item item in items)
        {
            Console.WriteLine($"Item's name : {item.Name}, Item's Group : {item.Group.ToString()}");

        }
    }
}

Outputs

  • Item’s name : Item 1, Item’s Group : group1
  • Item’s name : Item 2, Item’s Group : group2
  • Item’s name : ITEM 3, Item’s Group : group3

C# : Overriding Equality for Reference Types

Procedure for implementing equality for Reference Types:

  • Override object.Equals()
  • Override object.GetHashCode()
  • Implement == and != overloads

NOTE

  • IEquatable is only appropriate for sealed types : Due to inheritance. You may not be using the overloaded .Equals method and the compiler will not understand how to check for equality if you are using the base class Equal method.

  • Equality logic should go in the object.Equals method when overriding.

C# : Equality Operators and Methods for Value Types

Why change operations for equality checking for value types?

  • operator == does not work for value types. : That is why we have to overload the base method for == and !=
  • The Equals method boxes and unboxes values types that causes poor performance.
  • The Equals default method checks each field for equality.

Create our own equality comparison by overload methods for our custom value type classes.

Must do all three of these to keep you class consistent.

  • Override object.Equals : Avoid reflection
  • Implement IEquatable : Avoid unboxing, Make type safe
  • Provide implementation of C#’s == operator

Also override the Object.GetHashCode method, when overriding the Object.Equals method.

  • Override the Object.GetHashCode method

Exmaple Code :

public struct Item : IEquatable<Item> {
    public static bool operator ==(Item lhs, Item rhs){
       return lhs.Equals(rhs);
    }

    public static bool operator !=(Item lhs, Item rhs){
       return !lhs.Equals(rhs);
    }

    public book Equals(Item other){ 
       return this._name == other._name; 
    }

    public override bool Equals(object obj){ 
       if(obj is Item){ 
         return Equals(Item(obj)); 
      } else { 
        return false; 
     }

    public override int GetHashCode(){
        return _name.GetHashCode() ^ _group.GetHashCode();
    }
 } 

}

C# : Override Operators == and != along with .Equals : Reference Types

When comparing “reference” types in c# with operators == and !=, we should overwrite these operators to perform comparison checks on the reference type’s specific value field or multiple fields. C# provides operators == and != to compare reference types by checking if they point to the same object in memory versus comparing if the two objects are equal. If we would like to design our comparison operators of == and != to return a comparison of the objects specific field then we must overwrite the operators our self.

Best Practice

** Overwrite the Equals method from the base class “Object” as well. This will keep the equality operators in sync for other developers that may use your class and its compare features. It is also best practice to always use the “Equals” method to check the equality of any reference type. Using operators causes issues when using generics.

private string _name;

public static bool operator == (Product prod1, Product prod2)
{
    if(prod1.Name.Equals(prod2.Name)){
        return true;
    } else {
        return false;
    }
}

public static bool operator != (Product prod1, Product prod2)
{
    if(!prod1.Name.Equals(prod2.Name)){
        return true;
    } else {
        return false;
    }
}

public overwrite bool Equals(Product first, Product second)
{
   if(first == null || second == null){
     return false;
   }

   if(first.Name == second.Name){
     return true;
   } else {
     return false;
   }
}

public string Name {
    get {
        return _name;
    }
    set {
        this._name = value.ToUpper();
    }
}