2008-10-31 22 views
16

今天我碰巧發現一個C#類可以以隱式和顯式方式繼承一個接口。這讓我感到驚訝。如果C#以這種方式工作,則以不同方式引用時,一個實例的行爲可能會有所不同。爲什麼C#類可以隱式地和顯式地從一個接口繼承?

interface IFoo 
{ 
    void DoSomething(); 
} 

class Foo : IFoo 
{ 
    #region IFoo Members 
    public void DoSomething() 
    { 
     Console.WriteLine("do something implicitly"); 
    } 
    #endregion 

    #region IFoo Members 
    void IFoo.DoSomething() 
    { 
     Console.WriteLine("do something explicitly"); 
    } 
    #endregion 
} 


     Foo f = new Foo(); 
     f.DoSomething(); 

     ((IFoo)f).DoSomething(); 

上面的代碼運行並輸出

do something implicitly 
do something explicitly 

我相信,這種設計的C#使行爲的不一致性。也許這是強制性的,一個C#類可以以隱式或expliict方式從一個接口繼承,但不能同時接受。

有什麼理由說爲什麼C#是這樣設計的?

+0

我沒有注意到你可以同時做到這一點。這似乎有點傻... – 2008-10-31 10:26:41

+0

這並不傻。閱讀答案。 – 2008-10-31 10:39:25

+0

對不起,我試圖添加「顯式接口成員實現」作爲標籤(這是你使用的功能的名稱),但顯然標籤會太長。 :) – Rytmis 2008-10-31 11:11:03

回答

11

您的示例確實不是隱式和顯式實現IFoo。你只明確實現IFoo.DoSometing()。您的課堂上有一個名爲DoSomething()的新方法。它與IFoo.DoSomething無關,只是它具有相同的名稱和參數。

13

每個實現接口的類都有一個映射該類的成員和接口的成員之間。如果類明確地實現了接口成員,那麼顯式實現將總是被映射到接口。如果沒有明確的實現,那麼隱含的實現將被預期,並且那個將被映射到接口。

當一個類具有相同的會員名稱和相關類型的接口它也明確實施相應的成員的接口,那麼類的「隱性」的實施不是考慮到接口的實現根本不在(除非顯式實現調用它)。

除了在將類實現具有相同的部件名稱/類型的多個接口,即使只有一個接口每種情況下不同的含義,所述類本身被認爲具有可能具有相同的構件的隱式接口/類型作爲唯一的界面,但仍然意味着不同。

+0

這個隱式接口是一個實際的接口,還是僅僅暴露一個接口的類,即它是一種類型,儘管是一個隱藏的接口? – ProfK 2008-10-31 13:18:51

+0

我只是提到任何類的暴露。 CLR不會區分類的實現和其固有接口(即,除非接口是單獨定義的接口類型,否則不能實現另一個類的接口並替換它)。 – 2008-10-31 16:20:33

2

多重繼承: 如果從兩個定義相同方法的接口派生出來用於不同目的,該怎麼辦?

interface IMoveable 
    { 
    public void Act(); 
    } 

    interface IRollable 
    { 
    public void Act(); 
    } 

    class Thing : IMoveable, IRollable 
    { 
    //TODO Roll/Move code here 

    void IRollable.Act() 
    { 
     Roll(); 
    } 

    void IMoveable.Act() 
    { 
     Move(); 
    } 
    } 
7

這使得它在碰撞時更加靈活。特別是,請看IEnumeratorIEnumerator<T> - 他們都有Current屬性,但屬於不同的類型。你有使用明確的接口實現爲了實現兩者(和通用形式擴展非通用形式)。

0

夥計們,謝謝你的回答。事實證明,「C#類可以同時以隱式和顯式兩種方式繼承一個接口」實際上是一種錯覺。實際上,一個類可以一次繼承一個接口。

在原始問題中,「DoSomething」方法似乎「隱式實現」接口IFoo(該方法實際上由VS2008生成),但實際上並不是。通過顯式實現接口IFoo,「DoSomething」方法變成了與IFoo無關的普通方法,除非具有相同的簽名。

我仍然認爲這是C#的一個棘手的設計,並且很容易錯誤地使用它。說,我有這樣的代碼

 Foo f = new Foo(); 
     f.DoSomething(); 

現在,我想重構它到下面的代碼。看起來非常好,但執行結果不同。

 Action<IFoo> func = foo => foo.DoSomething(); 
     func(f);