扩展方法和编译时检查

Che*_*hen 5 .net c# linq extension-methods

也许有点棘手,但我想知道为什么.在System.Linq.Enumerable.csSystem.Core.dll,我们有:

public static int Count<TSource>(this IEnumerable<TSource> source);
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我正在做一些邪恶的事:

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();
   }
}
Run Code Online (Sandbox Code Playgroud)

如果我取消注释CommentedExtensions,我将收到一个编译错误,说"这个调用是不明确的blabla",如预期的那样.但为什么我第一次没有得到这个错误?这也很暧昧!

编辑经过另一次测试后,我发现如果扩展方法位于不同的命名空间中,我将不会遇到编译错误,即使它们完全相同.为什么允许这样做?它在c#中引入了模糊的方法调用.

EDIT2我知道其实两个Count在IL中是不同的.事实上它在呼唤

Enumerable.Count(Enumerable.Range(0,10))
Run Code Online (Sandbox Code Playgroud)

我的邪恶扩展方法是调用:

MyExtension.Count(Enumerable.Range(0,10))
Run Code Online (Sandbox Code Playgroud)

所以他们是不同的.但我仍然认为这是一种难闻的气味.我们有"真正的"扩展方法吗?哪个可以防止恶行为?

Jul*_*rau 4

C# 语言规范的第 7.6.5.2 节描述了编译器如何确定哪些扩展方法在范围内,以及哪些扩展方法优先于其他方法:

C [(候选扩展方法)] 的搜索按如下方式进行:

  • 从最接近的封闭命名空间声明开始,继续每个封闭命名空间声明,并以包含的编译单元结束,连续尝试查找扩展方法的候选集:
    • 如果给定的命名空间或编译单元直接包含具有合格扩展方法 Mj 的非泛型类型声明 Ci,则这些扩展方法的集合就是候选集
    • 如果在给定命名空间或编译单元中使用命名空间指令导入的命名空间直接包含具有合格扩展方法 Mj 的非泛型类型声明 Ci,则这些扩展方法的集合就是候选集。

这意味着,如果您的扩展方法与调用它们的代码位于同一名称空间中,则会选择这些扩展方法。将选择封闭命名空间中的扩展方法,而不是已导入的其他命名空间。