我从https://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx读到,基本类型上具有相同名称和签名的扩展方法永远不会被调用,但是“覆盖”扩展方法本身呢:
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
var query = (new[] { "Hans", "Birgit" }).Where(x => x == "Hans");
foreach (var o in query) Console.WriteLine(o);
}
}
public static class MyClass
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var obj in source)
if (predicate(obj)) yield return obj;
}
};
}
当我调试这个程序时,我会遇到我自己的扩展方法而不是System.Linq提供的那个(尽管包含了名称空间)。我是否遗漏了任何内容,或者扩展方法是否优先考虑?
答案 0 :(得分:11)
当编译器搜索扩展方法时,它从在与调用代码相同的命名空间中的类中声明的那些方法开始,然后向外工作直到它到达全局命名空间。因此,如果您的代码位于命名空间Foo.Bar.Baz
中,它将首先搜索Foo.Bar.Baz
,然后搜索Foo.Bar
,然后搜索Foo
,然后搜索全局命名空间。一旦找到任何符合条件的扩展方法,它就会停止。如果它在同一步骤中找到多个符合条件的扩展方法,则没有一个是&#34;更好&#34;比另一个(使用正常的重载规则),你会得到一个模糊的编译时错误。
然后(如果它没有找到任何东西)它会考虑using
指令导入的扩展方法。因此,如果将扩展方法移动到与您无关的不同命名空间,则由于模糊性(如果使用using
指令导入命名空间)或者它导致编译时错误只会找到System.Linq
方法(如果您没有导入包含方法的命名空间)。
这在C#规范的第7.6.5.2节中规定。
答案 1 :(得分:3)
以下是五个可能的Where<>
方法的较长示例:
using System;
using System.Collections.Generic;
using System.Linq; // **OUTSIDE**
namespace Me.MyName
{
using System.MySuperLinq; // **INSIDE**
static class Test
{
static void Main()
{
(new[] { "Hans", "Birgit" }).Where(x => x == "Hans");
}
}
}
namespace System.MySuperLinq
{
static class Extensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
Console.WriteLine("My own MySuperLinq method");
return null; // will fix one day
}
}
}
namespace Me.MyName
{
static class Extensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
Console.WriteLine("My own MyName method");
return null; // will fix one day
}
}
}
namespace Me
{
static class Extensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
Console.WriteLine("My own Me method");
return null; // will fix one day
}
}
}
// this is not inside any namespace declaration
static class Extensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
Console.WriteLine("My own global-namespace method");
return null; // will fix one day
}
}
尝试连续删除首选的方法,以查看&#34;优先级&#34; C#编译器使用。
Me.MyName
命名空间内搜索静态类,因为那是&#34;当前&#34;命名空间。System.MySuperLinq
中搜索,因为using
在里面。Me
命名空间null
)命名空间中搜索。System
,System.Collections.Generic
和System.Linq
。如果在一个&#34;级别找到两个或更多同样相关的方法&#34; (上面的子弹),这是编译时的歧义(不会编译)。