2011-09-22 183 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的實例;它只是查看變量聲明的類型。