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
IEnumerableargument 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