Why does the compiler choose overload with IEnumerable instead of 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 to call the generic LINQ method Enumerable.Contains<T> (type arguments obtained from use). However, I found that it actually calls the first method (my 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-universal argument IEnumerable Enumerable.Contains<T>() with argument IEnumerable<T> ? I expect it to select Enumerable.Contains<T>() because IEnumerable<T> is more derived than IEnumerable .
My question is: why does the compiler select my Contains () method with an
IEnumerableargument with a non-genericIEnumerableargument with anIEnumerable<T>argument?
Because it is found in the same namespace that contains the method that calls it. Types declared in this namespace take precedence over types declared in imported namespaces.
From the C # 5 specification, section 7.6.5.2:
Search C continues as follows:
- Starting with the nearest namespace declaration declaration, continuing with each namespace declaration declaration and ending with the containing compilation unit, successive attempts are made to find a set of candidates for extension methods:
- If a given namespace or compilation unit directly contains declarations of a non-general type Ci with suitable extension methods Mj, then the set of these extension methods is a set of candidates.
- If namespaces imported using namespace directives in a given namespace or into a compilation unit contain only general declarations of Ci with suitable extension methods Mj, then the set of these extension methods is a set of candidates.
- If a candidate set is not found in any namespace declaration declaration or in the compiler, a compile-time error occurs.