Search code examples
c#linqexceptiequalitycomparer

Difference between two overloads of Enumerable.Except?


I am trying to understand the difference between two overloads of Enumerable.Except method i.e.

  • Except(IEnumerable, IEnumerable)
  • Except(IEnumerable, IEnumerable, IEqualityComparer)

Obviously, the first differnce is that the first overload uses the default equality comparer while the other uses an IEqualityComparer, but I can achieve the same result with first method, by implementing an IEquatable interface (as mentioned in the MSDN documentation of Except method), then why this second overload is needed?


Solution

  • Two reasons:

    1. You can only implement IEquatable<T> for your own types... whereas you can specify an IEqualityComparer<T> for any type, whether you can modify it yourself or not.

    2. There may be multiple ways of comparing a type for equality, but implementing IEquatable<T> only allows you to express one of them.

    A simple example of all of this would be strings - consider:

    string[] x = { "A", "B", "C" };
    string[] y = { "A", "c" };
    
    var bc = x.Except(y);
    var justB = x.Except(y, StringComparer.OrdinalIgnoreCase);
    

    We might want both results in different circumstances, which means we couldn't handle both with IEquatable<T>... and we can't change how string implements IEquatable<T> anyway. (You're not limited to StringComparer of course - you could write an equality comparer which just used the length of the string, for example.)

    This isn't specific to LINQ, either - it's generally the case for any API which deals in equality, e.g. HashSet<>, Dictionary<,> etc.