Thursday, March 1, 2007

Why IEquatable ?

In the .net framework 2.0, a new interface IEquatable<T> has been introduced. Implementing it in your classes would give you a type safe way of equating your class instances.

The default .equals of the System.Object does a reference check and is not particularly useful when you want to equate instances of your class based on say certain fields. The workaround in .net 1.1 was to override the .equals(object o) , but this meant that additional type checking had to be done. Now with Generics,
IEquatable<T> gives you a type safe method to implement your class instance equality check.

I wrote some simple code to figure it all out:

First, A class which doesn't implement IEquatable ....


using System;

namespace test
{
class RegularAnimal :Animal
{



public RegularAnimal(int legs, string sound, string species)
{
this.legs = legs;
this.sound = sound;
this.species = species;

}

public void Introduce()
{
Console.WriteLine("I am a regular " + species + " I have " + legs.ToString() + " legs and I " + sound);
}


}
}


Now the same class that implements IEquatable<T>


using System;


namespace test
{

class EquatableAnimal : Animal, IEquatable<EquatableAnimal>
{

public EquatableAnimal(int legs, string sound, string species)
{
this.legs = legs;
this.sound = sound;
this.species = species;

}

public void Introduce()
{
Console.WriteLine("I am an equatable " + species + " I have " + legs.ToString() + " legs and I " + sound);
}


public bool Equals(EquatableAnimal other)
{
return (this != null && this.sound == other.sound);
}


}

}

Now some code to put the classes to test:


static void Main(string[] args)
{


RegularAnimal regular_cat = new RegularAnimal(4, "meow", "cat");
RegularAnimal regular_dog = new RegularAnimal(4, "bark", "dog");
RegularAnimal regular_siameseCat = new RegularAnimal(4, "meow", "siamese cat");

regular_cat.Introduce();
regular_dog.Introduce();
regular_siameseCat.Introduce();
IsEqual(regular_cat, regular_dog);
IsEqual(regular_cat, regular_siameseCat);

EquatableAnimal cat = new EquatableAnimal(4, "meow", "cat");
EquatableAnimal dog = new EquatableAnimal(4, "bark", "dog");
EquatableAnimal siameseCat = new EquatableAnimal(4, "meow", "siamese cat");
cat.Introduce();
dog.Introduce();
siameseCat.Introduce();
IsEqual(cat, dog);
IsEqual(cat, siameseCat);



}

public static void IsEqual(EquatableAnimal animal1, EquatableAnimal animal2)
{
if (animal1.Equals(animal2))
{
Console.WriteLine("We are the same: " + animal1.species + " and " + animal2.species);
}
else
{
Console.WriteLine("We are not the same: " + animal1.species + " and " + animal2.species);
}
}
public static void IsEqual(RegularAnimal animal1, RegularAnimal animal2)
{
if (animal1.Equals(animal2))
{
Console.WriteLine("We are the same: " + animal1.species + " and " + animal2.species);
}
else
{
Console.WriteLine("We are not the same: " + animal1.species + " and " + animal2.species);
}
}



The results(click on the picture to enlarge):


I am a regular cat I have 4 legs and I meow
I am a regular dog I have 4 legs and I bark
I am a regular siamese cat I have 4 legs and I meow
We are not the same: cat and dog
We are not the same: cat and siamese cat
I am an equatable cat I have 4 legs and I meow
I am an equatable dog I have 4 legs and I bark
I am an equatable siamese cat I have 4 legs and I meow
We are not the same: cat and dog
We are the same: cat and siamese cat
Press any key to continue . . .







The 'EquatableAnimal' compares the 'sound' field to identify animals of the same species while the RegularAnimal equality check fails since we are not overriding the Object.equals(Object o).If we had gone that route instead of implementing the IEquatable interface, we'd need to introduce this code in the RegularAnimal class:


public override bool Equals(object obj)
{
return ((obj != null) && (obj.GetType() == this.GetType()) && ((RegularAnimal)obj).sound == this.sound);


}





Useful links:
http://www.microsoft.com/mspress/books/sampchap/5353.aspx
http://msdn2.microsoft.com/en-us/library/ms131187.aspx
http://msdn2.microsoft.com/en-us/library/ms379564(vs.80).aspx

1 comment:

Geert Verhoeven said...

Be aware that some classes still use the Object.Equals method even when you implemented the IEquatable interface.

I've posted a sample code to show you when it can go wrong at CodeProject and on my blog.