6

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 ?

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • What do you not understand? The benefit of instantiating `IEqualityComparer.Default`, or why you can choose a specific instantiation, or something else? – thecoop Mar 11 '12 at 11:23
  • why does it work with or withOUT it , and why do i have a reason to call it with type – Royi Namir Mar 11 '12 at 11:34
  • 1
    Boxing only happens for value types. Since `Person` is a reference type, there is no boxing involved in this case. – thecoop Mar 11 '12 at 11:49
  • @thecoop you cant do `bool b = lst1.SequenceEqual(lst2,EqualityComparer.Default);` becuase it requires : Tsource type. and the Tsource is Person. – Royi Namir Mar 11 '12 at 11:52
  • Looks like there's a big misunderstanding of what's going on. Probably better if we take this to the C# chatroom... – thecoop Mar 11 '12 at 11:54

3 Answers3

2

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.

thecoop
  • 45,220
  • 19
  • 132
  • 189
  • this is because its `contravariant`. why would i want to use object comparer when its a Person ? Also, Ive heard that it has the advantage of avoiding boxing. which boxing ? something like : "if you have the Iequatable Equals method - I will use it and not The Object.Equals method"....where is that here ? – Royi Namir Mar 11 '12 at 11:43
  • 1
    In this particular example, generic contravariance isn't really that useful, however there are situations in which it is very useful indeed. Just because you are able to do something doesn't mean that it is right or correct to do so. – thecoop Mar 11 '12 at 11:46
1

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.

Andre Loker
  • 8,368
  • 1
  • 23
  • 36
0

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.