What's the difference between IEquatable and just overriding Object.Equals()?
C#.NetEqualsEqualityIequatableC# Problem Overview
I want my Food
class to be able to test whenever it is equal to another instance of Food
. I will later use it against a List, and I want to use its List.Contains()
method. Should I implement IEquatable<Food>
or just override Object.Equals()
? From MSDN:
> This method determines equality by
> using the default equality comparer,
> as defined by the object's
> implementation of the
> IEquatable
So my next question is: which functions/classes of the .NET framework make use of Object.Equals()
? Should I use it in the first place?
C# Solutions
Solution 1 - C#
The main reason is performance. When generics were introduced in .NET 2.0 they were able to add a bunch of neat classes such as List<T>
, Dictionary<K,V>
, HashSet<T>
, etc. These structures make heavy use of GetHashCode
and Equals
. But for value types this required boxing. IEquatable<T>
lets a structure implement a strongly typed Equals
method so no boxing is required. Thus much better performance when using value types with generic collections.
Reference types don't benefit as much but the IEquatable<T>
implementation does let you avoid a cast from System.Object
which can make a difference if it's called frequently.
As noted on Jared Parson's blog though, you must still implement the standard Object.Equals
and Object.GetHashcode
overrides.
Solution 2 - C#
According to the MSDN:
> If you implement IEquatable<T>
, you
> should also override the base class
> implementations of
> Object.Equals(Object)
and GetHashCode
> so that their behavior is consistent
> with that of the IEquatable<T>.Equals
> method. If you do override
> Object.Equals(Object)
, your overridden
> implementation is also called in calls
> to the static Equals(System.Object, > System.Object)
method on your class.
> This ensures that all invocations of
> the Equals
method return consistent
> results.
So it seems that there's no real functional difference between the two except that either could be called depending on how the class is used. From a performance standpoint, it's better to use the generic version because there's no boxing/unboxing penalty associated with it.
From a logical standpoint, it's also better to implement the interface. Overriding the object doesn't really tell anyone that your class is actually equatable. The override may just be a do nothing class or a shallow implementation. Using the interface explicitly says, "Hey, this thing is valid for equality checking!" It's just better design.
Solution 3 - C#
Extending what Josh said with a practical example. +1 to Josh - I was about to write the same in my answer.
public abstract class EntityBase : IEquatable<EntityBase>
{
public EntityBase() { }
#region IEquatable<EntityBase> Members
public bool Equals(EntityBase other)
{
//Generic implementation of equality using reflection on derived class instance.
return true;
}
public override bool Equals(object obj)
{
return this.Equals(obj as EntityBase);
}
#endregion
}
public class Author : EntityBase
{
public Author() { }
}
public class Book : EntityBase
{
public Book() { }
}
This way, I have re-usable Equals() method that works out of the box for all my derived classes.
Solution 4 - C#
If we call object.Equals
, it forces to expensive boxing on value types. This is undesirable in performance-sensitive scenarios. The solution is to use IEquatable<T>
.
public interface IEquatable<T>
{
bool Equals (T other);
}
The idea behind IEquatable<T>
is that it gives the same result as object.Equals
but more quickly. The constrain where T : IEquatable<T>
must be used with generic types like below.
public class Test<T> where T : IEquatable<T>
{
public bool IsEqual (T a, T b)
{
return a.Equals (b); // No boxing with generic T
}
}
otherwise, it binds to slower object.Equals()
.