2009-02-13 43 views
5

我結束了類似下面的代碼在我正在處理的項目中的代碼。我認爲我被允許這樣做真的很奇怪,但是現在我開始想知道我最喜歡的一個建築大師是什麼讓我這麼做的。使用界面組合怪誕怪異的界面多態性

我的問題,你是:

  • 到底是該叫什麼?
  • 這有什麼真實世界的用途?
  • 爲什麼有人想要這樣做?

這裏是我的接口:

namespace ThisAndThat 
{ 
    public interface ICanDoThis 
    { 
     string Do(); 
    } 

    public interface ICanDoThat 
    { 
     string Do(); 
    } 

    public interface ICanDoThisAndThat : ICanDoThis, ICanDoThat 
    { 
     new string Do(); 
    } 
} 

這裏是我的具體類:

namespace ThisAndThat 
{ 
    public class CanDoThisAndThat : ICanDoThisAndThat 
    { 
     public string Do() 
     { 
      return "I Can Do This And That!"; 
     } 

     string ICanDoThis.Do() 
     { 
      return "I Can Do This!"; 
     } 

     string ICanDoThat.Do() 
     { 
      return "I Can Do That!"; 
     } 
    } 
} 

與我擦肩而過的測試:

using Xunit; 

namespace ThisAndThat.Tests 
{ 
    public class ThisAndThatTests 
    { 
     [Fact] 
     public void I_Can_Do_This_And_That() 
     { 
      ICanDoThisAndThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This And That!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_This() 
     { 
      ICanDoThis sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_That() 
     { 
      ICanDoThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do That!", sut.Do()); 
     } 

    } 
} 

回答

5

這段代碼絕對沒有錯(只要它不會讓你的用戶感到困惑),它不是一個我熟悉的任何名字的模式。 CanDoThisAndThat實現了兩個接口,因此客戶端可以以任何方式使用它。

.NET允許以這種方式實現接口 - 被稱爲顯式接口實現。當

顯式接口實現是有用的:

  1. 兩個接口具有相同的成員定義
  2. 你需要實現一個接口,但不希望宣傳一個特定的成員是提供給客戶端的代碼,尚未使用接口類型聲明參考

.NET框架中的情況2的示例是ICollection.SyncLockList<T>實現ICollection但下面的代碼將無法編譯,因爲該成員已有意「隱藏」的BCL的設計師不再提倡用這種方式鎖定類別:

List<object> list = new List<object>(); 

lock (list.SyncRoot) // compiler fails here 
{ 
    // ... 
} 

這種格式的任何遺留代碼仍然可以工作,因爲ICollection明確提到:

ICollection list = new List<object>(); 

lock (list.SyncRoot) // no problem 
{ 
    // ... 
} 
+0

謝謝,給你答案,因爲你提供了正確的名稱。 – 2009-02-14 20:01:50

4

每種類型都有一個interface mapping(可如果你使用Type.GetInterfaceMap檢索nt用反射來看它)。這基本上說,「當調用接口Y上的方法X時,此方法Z是要調用的方法。」請注意,即使它不受C#支持,但映射目標方法可能與接口方法名稱具有不同的名稱! (VB明確支持這一點,我相信)。

在你的情況,你有三種方法,三種方法中的每一種都對應於其中一個接口中的方法。

當編譯器通過接口向虛擬方法發出調用時,IL生成的內容如「在此對象上調用IFoo.Bar」 - 然後使用接口映射解析IFoo.Bar。

如果您的簽名只在返回類型上有所不同,或者您要實現兩個碰巧擁有相同方法名稱但應該做不同事情的異構接口,有時可能需要使用它。無論你在哪裏都可以儘管避免它,做!它使代碼非常混亂。