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
.
My question is, why does the compiler choose my Contains() method with non-generic
IEnumerable
argument overEnumerable.Contains<T>()
withIEnumerable<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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With