views:

1924

answers:

2

IEnumberable has an extension method Contains<T> which takes two parameters. The first parameter is the value to check for and the second is an implementation of IEqualityComparer. Looking at IEqualityComparer.Equals it takes two parameters named x and y, for the first and second objects to compare.

My question is X or Y the value from the IEnumerable?

Example

List<string> test = new List<String() { "a", "b", "c" };
test.Contains("d", myComparer);

When it calls to the Equals method for the first value will it be Equals("a","d") or Equals("d","a")?

+3  A: 

It shouldn't matter - equality should be symmetric. From the docs for IEqualityComparer<T>.Equals:

The Equals method is reflexive, symmetric, and transitive. That is, it returns true if used to compare an object with itself; true for two objects x and y if it is true for y and x; and true for two objects x and z if it is true for x and y and also true for y and z.

I don't believe the usage in Enumerable.Contains is well-defined, i.e. it could change in a future version. If you just make your equality comparer obey the interface documentation, you'll be fine.

Jon Skeet
It still always amuses me that IComparer<T> is *not* required to be transitive... and indeed, isn't for string
Marc Gravell
+1  A: 

For the sake of completeness the reflected code of IEnumberable shows it is on the left hand side (see below). However that is not promised not to ever change, so there is risk in using it.

public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
{
    if (comparer == null)
    {
        comparer = EqualityComparer<TSource>.Default;
    }
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    foreach (TSource local in source)
    {
        if (comparer.Equals(local, value))
        {
            return true;
        }
    }
    return false;
}
Robert MacLean