2011-09-22 192 views
12

我对扩展方法如何工作有点困惑。C#扩展方法优先

如果我正确阅读这个http://msdn.microsoft.com/en-us/library/bb383977.aspx和这If an extension method has the same signature as a method in the sealed class, what is the call precedence?

然后下面应该写出“实例”,而是写入“扩展方法”。

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(); 
    } 
} 

感谢任何帮助澄清行为。

+0

你确定用扩展方法编译的内置方法重写吗? – kenny

+0

乍一看或编译它时,界面没有Say(),所以你所称的扩展方法。在接口中使用Save()时,编译器会抱怨'C:\ projects \ _play \ ExtensionMethods \ Program.cs(2,1):错误CS0116:名称空间不能直接包含成员,如字段或方法' – kenny

回答

14

这里最大的区别在于您已为IFoo接口定义了扩展方法,而foo变量的类型为IFoo

如果你的代码是这个样子:

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

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

我希望我能给你一个彻底的解释,为什么这是,但我只能涵盖基本机制。因为你的变量是IFoo类型,而不是Foo,所以当编译器试图确定哪些方法可用时,它查看Foo类的任何非接口方法(它应该)。然而,扩展方法Say()可用,所以它调用了这个。

+2

要添加到此,当你使用IFoo foo = ..时,即使它指向一个Foo实例,foo的类型也是IFoo。 'Foo foo ...'在对象上调用方法,'IFoo foo'使'Say()'展开为'FooExts.Say(foo)'。运行'ildasm'并将.exe放入其中以查看IL。 –

+0

感谢Jim提示。 – Dax70

4

在您的Main, foo被宣布为IFoo。当编译器查找方法Say时,它只能找到扩展方法。这是因为实例方法在Foo中声明,而不是在IFoo中声明。编译器不知道变量foo碰巧包含Foo的实例;它只是查看变量声明的类型。