3/9/13

.NET interfaces Part 3

IEqualityComparer<T>

 public interface IEqualityComparer<in T>
 {
        bool Equals(T x, T y);        
        int GetHashCode(T obj);
 }
 
When to use it:
Let us say you have a custom Type and you plan to use instances of that type in a collection. If you want to use methods like List<T>.contains or Dictionary<T1,T2>.Add, you will need to way to check if an item in your collection equals the item we are trying to find.To facilitate this you can implement the IEqualityComparer<T>.

How is it different from IEquatable<T>?
For every custom type that you wish to check for Equality, you will need to implement the IEquatable<T> interface. But if you have a set of related base/child classes that share a common Equality check functionality, you need to create just one IEqualityComparer<T> where T is the Base type and use it with all other types.

public abstract class Star
    {
        public int Age { get; set; }
        public int GamesPlayed { get; set; }
        public int PointsScored { get; set; }
    }

    public class FootballStar : Star
    {
       
    }

    public class BaseballStar : Star
    {

    }

    //This comparer can be used by all instances of type Star 
    public class StarComparer: IEqualityComparer<Star>
    {
        //strongly typed input parameter
        public bool Equals(Star input1, Star input2)
        {
            if (input1.GamesPlayed == input2.GamesPlayed && 
                  input1.PointsScored == input2.PointsScored) 
               return true;
            return false;
        }
        
        public int GetHashCode(Star input)
        {
            //the XOR value
            return input.GamesPlayed ^ input.PointsScored;
        }
    }

    //calling code
    class Program
    {
        static void Main(string[] args)
        {
     FootballStar Brady = new FootballStar() 
                   { Age = 35, GamesPlayed = 900, PointsScored = 55000 };
            FootballStar Peyton = new FootballStar() 
                   { Age = 35, GamesPlayed = 500, PointsScored = 30000 };
            FootballStar Rodgers = new FootballStar() 
                   { Age = 28, GamesPlayed = 500, PointsScored = 31000 };
            FootballStar Griffin = new FootballStar() 
                   { Age = 28, GamesPlayed = 400, PointsScored = 20000 };

            List FootballStars = new List() 
                   {Brady, Peyton, Rodgers, Griffin};
            
            FootballStar Peyton2 = new FootballStar() 
                  { Age = 35, GamesPlayed = 500, PointsScored = 30000 };

            /* the Equals method of the comparer will be used to 
                  determine the equality
               */
    Console.WriteLine(FootballStars.Contains(Peyton2,new StarComparer()));

            /* Add internally calls GetHashCode of the StarComparer 
                  and will not let you add two keys with the same HashCode
               */
         Dictionary StarDictionary = new Dictionary(3,new StarComparer());
            StarDictionary.Add(Brady, "Patriots");
            StarDictionary.Add(Peyton, "Denver");
            StarDictionary.Add(Rodgers, "Greenbay");
            StarDictionary.Add(Griffin, "Washington");

            //Contains and ContainsKey will both internally call 
            //comparer's Equals and GetHashCode methods
            Console.WriteLine(StarDictionary.ContainsKey(Peyton2));
   Console.WriteLine(StarDictionary.Contains(new KeyValuePair(Peyton2, "Denver")));
 }
}
NOTE:
Since the type T of the comparer is of type Star, any types that derive from it can use the same equality comparer as long as they wish to use the same criteria for determining equality. e.g. if the instances of the type BaseballStar were used in a collection, we can use the same EqualityComparer to test for Equality since BaseballStar inherits from Star

No comments: