Maybe a little tricky, but I wonder why. In System.Linq.Enumerable.cs
of System.Core.dll
we have:
public static int Count<TSource>(this IEnumerable<TSource> source);
In my code I'm doing something evil:
namespace Test
{
public static class Extensions
{
public static int Count<TSource>(this IEnumerable<TSource> source)
{
return -1; //evil code
}
}
//commented temporarily
//public static class CommentedExtensions
//{
// public static int Count<TSource>(this IEnumerable<TSource> source)
// {
// return -2; //another evil code
// }
//}
public static void Main(string[] args)
{
Console.WriteLine(Enumerable.Range(0,10).Count()); // -1, evil code works
Console.Read();
}
}
If I uncomment CommentedExtensions
, I'll get a compile error saying "this call is ambiguous blabla" as expected. But why I didn't get this error at the first time? It's also ambiguous!
EDIT After another test, I found that I won't get compile errors if the extension methods are in different namespaces, even they are completely the same. Why it's allowed? It brings ambiguous call of methods in c#.
EDIT2 I know in fact the two Count
are different in IL. In fact it's calling
Enumerable.Count(Enumerable.Range(0,10))
and my evil extension method is calling:
MyExtension.Count(Enumerable.Range(0,10))
so they are different. But still I think it's a bad smell. Do we have "real" extension methods? which can prevent the evil behavior?
Section 7.6.5.2 of the C# language specification describes how the compiler determines which extension methods are in scope, and which extension methods take precedence over others :
The search for C [(a candidate extension method)] 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.
Meaning that if you have extension methods in the same namespace than the code from which you call them, these extension methods are selected. Extension methods in an enclosing namespace will be choosed over other namespaces that have been imported.
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