Why does the compiler choose override with IEnumerable over IEnumerable<T>?

Consider the following two extension methods:

using System;
using System.Collections.Generic;
using System.Linq;

public static class Extensions
{
    public static bool Contains(this IEnumerable self, object obj)
    {
        foreach (object o in self)
        {
            if (Object.Equals(o, obj))
            {
                return true;
            }
        }
        return false;
    }

    public static bool ContainsEither<T>(this IEnumerable<T> self, T arg1, T arg2)
    {
        return self.Contains(arg1) || self.Contains(arg2);
    }
}

When I wrote my second method, I intended it to call the generic LINQ Enumerable.Contains<T> method (type arguments inferred from the usage). However, I found out that it is actually calling the first method (my custom Contains() extension method. When I comment out my Contains() method, the second method compiles fine, using the Enumerable.Contains<T>() method.

My question is, why does the compiler choose my Contains() method with non-generic IEnumerable argument over Enumerable.Contains<T>() with IEnumerable<T> argument? I would expect it to choose Enumerable.Contains<T>() because IEnumerable<T> is more derived than IEnumerable.

Update: Thanks to Jon Skeet for the great answer. It would be interesting to know why the designers chose this way. I spent some time exploring cases where this would matter, I thought of one (granted it's a bit of a reach)

public static double Average(this IEnumerable self)
{
    double sum = 0;
    long count = 0;
    foreach (object obj in self)
    {
        sum += Convert.ToDouble(obj);
        nItems++;
    }
    return sum / count;
}

object[] junk = new object[] { "9000", (byte)99, -8.555, 3154254325345UL };
double[] clean = new double[] { 9000, 99, -8.555, 3154254325345 };
double junkAvg = junk.Average();
double cleanAvg = clean.Average(); // compiler is choosing your Average() method where you'd prefer it to choose Enumerable.Average(IEnumerable<double>)
Jon Skeet
people
quotationmark

My question is, why does the compiler choose my Contains() method with non-generic IEnumerable argument over Enumerable.Contains<T>() with IEnumerable<T> argument?

Because it's found in the same namespace that contains the method calling it. Types declared within that namespace effectively have precedence over types declared in imported namespaces.

From the C# 5 specification, section 7.6.5.2:

The search for C proceeds as follows:

  • Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
    • If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
    • If namespaces imported by using namespace directives in the given namespace or compilation unit directly contain non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
  • If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.

people

See more on this question at Stackoverflow