C#扩展方法优先级

13
我对扩展方法的工作原理有点困惑。
如果我读得正确,那么根据http://msdn.microsoft.com/en-us/library/bb383977.aspx这里的解释,以下代码应该输出“Instance”,但实际上输出的是“Extension method”。
interface IFoo
{
}

class Foo : IFoo
{
    public void Say()
    {
        Console.WriteLine("Instance");
    }
}

static class FooExts
{
    public static void Say(this IFoo foo)
    {
        Console.WriteLine("Extension method");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IFoo foo = new Foo();
        foo.Say();
    }
}

非常感谢帮助澄清此行为。


你确定使用扩展方法覆盖内置方法可以编译通过吗? - kenny
仔细看或编译它后,接口没有Say(),所以你调用了扩展方法。如果接口中有Save(),编译器会报错:'C:\projects_play\ExtensionMethods\Program.cs(2,1): error CS0116: A namespace cannot directly contain members such as fields or methods'。 - kenny
2个回答

15

这里的区别在于你定义了一个扩展方法来针对 IFoo 接口,而你的变量 foo 的类型是 IFoo

如果你的代码看起来像这样:

Foo foo = new Foo();
foo.Say()

执行的是Foo.Say()方法,而不是扩展方法。

我很希望能够给你一个详细的解释,但我只能提供基本机制的概要。因为你的变量类型是IFoo而不是Foo,所以当编译器尝试确定哪些方法可用时,它会忽略Foo类的任何非接口方法(这是正确的)。然而,扩展方法Say()是可用的,因此调用了它。


2
此外,当您使用 IFoo foo = .. 时,foo 的类型是 IFoo,即使它指向 Foo 的实例。Foo foo... 在对象上调用方法,而 IFoo foo 导致 Say() 扩展为 FooExts.Say(foo)。运行 ildasm 并将 .exe 放入其中以查看 IL。 - Joseph Yaduvanshi

4
在你的Main中,foo声明为IFoo。当编译器查找Say方法时,它只找到了扩展方法。这是因为实例方法声明在Foo中,而不是在IFoo中。编译器不知道变量foo恰好包含Foo的一个实例;它只看变量声明的类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接