Question

I have a class Person, it implements Equals() method from IEquatable<Person> (also overrides Object.Equals method, lets ignore the GetHashcode() method for now)

class Person : IEquatable<Person>
{
    public string Name { get; set; }

    public bool Equals(Person other)
    {
        return this.Name == other.Name;
    }
    public override bool Equals(object obj)
    {
        var person = obj as Person;
        return person != null && person.Name == Name;
    }
}

Ok, lets start:

Person p1 = new Person() { Name = "a" };
Person p2 = new Person() { Name = "a" };

List<Person> lst1 = new List<Person>() { p1 };
List<Person> lst2 = new List<Person>() { p2 };

Lets talk about this line :

 bool b = lst1.SequenceEqual(lst2, EqualityComparer<Person>.Default);

I have a problem understanding this part :

EqualityComparer<Person>.Default

I've heard that EqualityComparer<Person>.Default will check if the class is implementing IEquatable - it will take the Equals(Person other) Method and not the Equals(object obj). it has the advantage of avoiding boxing

enter image description here but

the Equals(Person other) will run with or withOUT EqualityComparer<Person>.Default (because it's implementing IEquatable)

So what Boxing are we talking about ? there isn't !

The only time that Equals(object obj) will run is when :

bool b = lst1.SequenceEqual(lst2,EqualityComparer<Object>.Default);

But I'm a programmer! I'll never Send an object when its actually a Person!

What am I missing? I'm having trouble understanding the benefit here of EqualityComparer<Object>.Default. Can someone please give me an example to prove me I'm wrong ?

Was it helpful?

Solution

If you pass in null as the second parameter or if you don't pass in a second argument at all (which is basically the same), the implementation of SequenceEquals will call EqualityComparer<T>.Default itself (decompile Enumerable to see this). That explains why you don't see a difference whether you provide EqualityComparer<T>.Default or not.

So in the end the second parameter only makes sense if you want to use an equality comparer other than EqualityComparer<T>.Default.

OTHER TIPS

That you can pass in IEqualityComparer<object>.Default is an effect of generic contravariance, added in .NET 4.

Essentially, an IEqualityComparer<BaseType> can be used whenever an IEqualityComparer<DerivedType> is required, where DerivedType : BaseType. Since Person derives from Object, this means that an IEqualityComparer<Object> can be used wherever an IEqualityComparer<Person> is required.

The answer is here: http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx

For a value type, you should always implement IEquatable and override Object.Equals(Object) for better performance. Object.Equals boxes value types and relies on reflection to compare two values for equality. Both your implementation of Equals and your override of Object.Equals should return consistent results.

If you do not override Equals and GetHashCode, EqualityComparer.Default actually takes care of that for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top