考虑以下程序:
class A
{
public static void Foo()
{
}
}
static class Ext
{
public static void Foo(this A a)
{
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
a.Foo();
}
}
这无法编译,错误如下:
无法使用实例引用访问成员'Test.A.Foo()';用类型名称来限定它
为什么编译器会忽略扩展方法?
问题是重载解决:静态方法 Foo()
是一个候选人,它适用 - 只是 选择 它作为最佳匹配将导致错误 - 这正是发生的事情。在考虑所有其他候选者之后,扩展方法仅是重载解决的候选者。在OPs问题的情况下,甚至在错误发生之前都不会考虑扩展方法。
你不想做什么。该 C#MSDN扩展方法文章 具体说明:
您可以使用扩展方法来扩展类或接口,但不能覆盖它们。永远不会调用与接口或类方法具有相同名称和签名的扩展方法。在编译时,扩展方法的优先级始终低于类型本身中定义的实例方法。
谢天谢地,这是不允许的,因为必须要维护才是可怕的。
编辑:所以人们都说静态方法不是实例方法,这是正确的。但试着这样做:
class A
{
public static void Foo() {}
public void Foo() {}
}
由于名称歧义,这不会编译。如果允许您使用扩展方法,那就是会发生什么。它会引入完全相同的歧义。现在,假设一个方法是静态的,一个是实例,那么这应该意味着没有歧义。但在目前的状态下,它确实引入了歧义,这是为什么不允许它的另一个原因。
编辑#2:来自评论@ErenErsonmez:
但是,只要扩展方法与实例方法没有相同的签名,我就不明白它是如何用静态方法引起歧义的
如果您更改扩展方法的签名,它肯定会起作用。所以以下内容将起作用:
class A
{
public static void Foo() { }
}
static class Ext
{
public static void Foo(this A me, int i)
{ }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Foo(10);
Console.ReadLine();
}
}
所以它看起来更像是一个含糊不清的问题而不是一个与已经存在的方法同名的扩展方法。
它来自 这篇MSDN文章 这是出于安全考虑。
我经常听到可以使用扩展方法的担忧
劫持或颠覆现有方法的预期行为。视觉
基本通过尽可能确保实例来确保这一点
方法优于扩展方法。
该语言允许使用扩展方法来创建重载
对于具有不同签名的现有实例方法。这允许
扩展方法用于创建重载,同时防止
来自被覆盖的现有实例方法。如果是扩展方法
存在与实例方法相同的签名,阴影
编译器内置的规则将更喜欢实例
方法,因此消除了扩展方法的可能性
覆盖现有的基类实例功能
这是以VB为重点(并且以实例为重点),但仍然是一般的想法。基本上,扩展方法采用最低优先级,因此方法不能被劫持,并且由于类已经有一个方法签名用于您尝试执行的操作,因此优先级会引发标准扩展方法错误(当尝试从实例对象)。你永远不会有两个具有相同签名的方法,这就是你要求在这里尝试的......并且允许它将是一个安全问题,如上所述。
然后,添加由此创建的混淆,允许它只是一个坏主意。