CSharpFeeds - All your C# feeds in one place.

Sponsors

Monday, September 29, 2008

IComparer vs IEqualityComparer

by Keyvan Nayyeri via Keyvan Nayyeri on 9/29/2008 6:37:44 PM

Working with collection types is a common task in modern software development and as a widespread development platform, .NET Framework is coming with a very rich set of collection types and features varying from traditional types such as arrays or ArrayList to modern generic types and very helpful extension methods that are offered for them in .NET 3.5.

As we move forward, we feel the necessity of having the capability to apply some operations like sort and search more than the past and accomplishing these tasks is the common scenario behind many of the extension methods in .NET 3.5.

The interesting point about performing these tasks is their dependency to two interfaces that are required for their internal operation and these two classes are IComparer and IEqualityComparer. In this post I want to give an introduction to these two classes and discuss their usage.

Background

First of all, let me give a short background about the samples that I’m going to present in this post. Here I define a very simple class called Person that represents a person with his name and blog URI.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace IComparerVsIEqualityComparer

{

    public class Person

    {

        #region Properties

 

        public string Name { get; set; }

 

        public Uri BlogUri { get; set; }

 

        #endregion

 

        #region Public Constructor

 

        public Person(string name, string blogUrl)

        {

            this.Name = name;

            this.BlogUri = new Uri(blogUrl);

        }

 

        #endregion

    }

}

Later in the post I will use collections of Person objects to perform some operations like sort and distinct select and exhibit the role of the abovementioned classes.

IComparer

The first interface to examine is the older class that has been a part of the .NET Framework since the first version, 1.0, to now, and that class is IComparer which is mainly responsible for comparing two objects of the same type, so it’s commonly used in the sort operations (and some other operations) in the .NET Framework.

IComparer appears as two types of interfaces in the .NET Framework: one is the traditional interface that can be implemented like regular interfaces and the other one is a generic interface that should be the preferred method of using this class. In either case there is a single Compare function that must be implemented which gets two objects as its parameters and returns an integer value. This integer value represents the comparison of two objects: if the first object is less than the second one then it returns a negative integer, and if both objects are equal then it returns a zero value otherwise it must return a positive integer.

In the below code I implement the generic interface for Person class in which I write a simple code that compares two objects and applies the CompareTo function of the string type as a helper. This implementation compares two Person objects based on the string order of their Name properties.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace IComparerVsIEqualityComparer

{

    public class PersonComparer : IComparer<Person>

    {

        #region IComparer<Person> Members

 

        public int Compare(Person x, Person y)

        {

            if (x.Name == y.Name)

                return 0;

            else

                return x.Name.CompareTo(y.Name);

        }

 

        #endregion

    }

}

Now I apply this implementation in a piece of code where I define a generic list of Person objects and call its Sort method by passing an instance of PersonComparer object.

private static void IComparerSample()

{

    Console.Title = "IComparer vs IEqualityComparer";

 

    List<Person> persons = new List<Person>();

    persons.Add(new Person("Keyvan Nayyeri", "http://nayyeri.net"));

    persons.Add(new Person("Simone Chiaretta", "http://codeclimber.net.nz/"));

    persons.Add(new Person("Phil Haack", "http://haacked.com/"));

    persons.Add(new Person("Scott Hanselman", "http://hanselman.com/blog/"));

 

    PersonComparer personComparer = new PersonComparer();

    persons.Sort(personComparer);

 

    foreach (Person person in persons)

    {

        Console.WriteLine("Name: {0} - Blog: {1}",

            person.Name, person.BlogUri.ToString());

    }

 

    Console.ReadLine();

}

The output of the code is predictable and is shown in the following figure.

Output

IEqualityComparer

The second interface, IEqualityComparer, is not as common as the first one but will have a more important role after the birth of LINQ because it plays a key role in collection operations like distinction or intersection. Like IComparer, IEqualityComparer has a traditional implementation as well as a generic interface.

This interface has two functions to implement: an Equals function that gets two objects of the same type and returns a Boolean value specifying if they are equal or not, and a GetHashCode function that gets an object and return the integer hash code representative of that object.

In the below code I implement this interface for Person class with a simple comparison between the name and blog URI of objects.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace IComparerVsIEqualityComparer

{

    public class PersonEqualityComparer : IEqualityComparer<Person>

    {

        #region IEqualityComparer<Person> Members

 

        public bool Equals(Person x, Person y)

        {

            if ((x.Name == y.Name) && (x.BlogUri == y.BlogUri))

                return true;

            else

                return false;

        }

 

        public int GetHashCode(Person obj)

        {

            return base.GetHashCode();

        }

 

        #endregion

    }

}

Applying this class in my sample, I can get the distinct collection of Person objects in the below code by passing an instance of this IEqualityComparer implementation to Distinct function.

private static void IEqualityComparerSample()

{

    Console.Title = "IComparer vs IEqualityComparer";

 

    List<Person> persons = new List<Person>();

    persons.Add(new Person("Keyvan Nayyeri", "http://nayyeri.net"));

    persons.Add(new Person("Scott Hanselman", "http://hanselman.com/blog/"));

    persons.Add(new Person("Simone Chiaretta", "http://codeclimber.net.nz/"));

    persons.Add(new Person("Phil Haack", "http://haacked.com/"));

    persons.Add(new Person("Keyvan Nayyeri", "http://nayyeri.net"));

    persons.Add(new Person("Scott Hanselman", "http://hanselman.com/blog/"));

 

    PersonEqualityComparer personEqualityComparer = new PersonEqualityComparer();

    persons = persons.Distinct(personEqualityComparer).ToList<Person>();

 

    foreach (Person person in persons)

    {

        Console.WriteLine("Name: {0} - Blog: {1}",

            person.Name, person.BlogUri.ToString());

    }

 

    Console.ReadLine();

}

Output

Conclusion

IComparer and IEqualityComparer play an important role in collection types to accomplish a variety of key operations. The main role of IComparer is to provide means to compare two objects and specify which one is greater than other, and the main role of IEqualityComparer is to compare two objects for equality, so IComparer has a more generic role than IEqualityComparer. Both interfaces are an inherent part of working with collection types in a professional level.

At the end, there is a sample code package available that you can download to get your hands on the code samples provided in this post.

email it!bookmark it!digg it!

Original Post: IComparer vs IEqualityComparer

Subscribe

New Feed

Product Spotlight

Recently Updated Sources

Legal Note

The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.

Advertise with us