2009-02-13 5 views
5

ich mit so etwas wie den folgenden Code in einem Projekt arbeite ich an gelandet. Ich dachte, es wäre wirklich seltsam, dass ich es tun durfte, aber jetzt beginne ich mich zu fragen, was höchstwahrscheinlich ein architektonischer Gaff ist, der mich dazu geführt hat.Freakishly seltsam Schnittstelle Polymorphismus Schnittstelle Zusammensetzung mit

Sie Meine Fragen sind:

  • Was genau heißt das?
  • Was sind einige reale Welt der diese verwendet?
  • Warum sollte jemand das tun?

Hier sind meine Schnittstellen:

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

    public interface ICanDoThat 
    { 
     string Do(); 
    } 

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

Hier ist meine konkrete Klasse:

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!"; 
     } 
    } 
} 

Und mein Vergehen Tests:

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

    } 
} 

Antwort

5

Es ist absolut nichts falsch mit diesem Code (vorausgesetzt es ist nicht verwirrend für Ihre Benutzer), und es ist kein Muster mit irgendeinem Namen, den ich kenne. CanDoThisAndThat implementiert zwei Schnittstellen, sodass Clients sie auf jede Art verwenden können.

.NET ermöglicht die Implementierung von Schnittstellen auf diese Weise - bekannt als explizite Schnittstellenimplementierung.

Explizite Schnittstellenimplementierung ist nützlich, wenn:

  1. Zwei Schnittstellen selben Mitglied Definition
  2. Sie haben brauchen eine Schnittstelle zu implementieren, aber nicht wollen, zu veröffentlichen, dass ein bestimmtes Mitglied zu Client-Code verfügbar ist, dass hat keine Referenz über den Schnittstellentyp

deklariert Ein Beispiel für Fall 2 aus dem .NET-Framework ist ICollection.SyncLock.List<T> implementiert ICollection noch der folgende Code wird nicht kompiliert, da das Mitglied hat befürworten wie die Designer des BCL nicht mehr absichtlich ‚versteckt‘ sind Sammlungen auf diese Weise Verriegelung:

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

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

Vermächtnissen Code dieses Format wird immer noch funktionieren da die Referenz vom Typ ICollection ausdrücklich:

ICollection list = new List<object>(); 

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

Danke, geben Sie die Antwort, weil Sie den genauen Namen der dargebotenen, was los ist. –

+0

Downvoted, da Sie eine Menge Fehler in Ihrer Antwort haben. Erstens implementiert die Klasse "CanDoThisAndThat" drei Schnittstellen, nicht zwei. 'ICanDothisAndThat' besagt, dass bei der Implementierung auch die beiden anderen Schnittstellen implementiert werden müssen. Außerdem wird SyncRoot nicht explizit durch Implementierungen definiert, um es zu verstecken, um die Verwendung zu verhindern, es wird normalerweise ausgeführt, um selten verwendete Mitglieder von der Site fernzuhalten, oder wenn die Tatsache, dass eine Schnittstelle implementiert ist, keine Rolle spielt. Sehen Sie sich http://msdn.microsoft.com/en-us/library/system.collections.icollection.syncroot.aspx und http://msdn.microsoft.com/en-us/library/bb356596.aspx an. – Andy

+0

Nein, wo in dieser Dokumentation steht, dass Sie SyncLock nicht verwenden sollten, noch sind sie als Veraltet markiert, was wirklich gemacht wird, wenn etwas nicht mehr verwendet werden sollte. – Andy

4

Jeder Typ hat eine interface mapping (die mit Type.GetInterfaceMap abgerufen werden, wenn Sie wa um es mit Reflexion zu betrachten). Dies bedeutet im Wesentlichen, "Wenn Methode X auf der Schnittstelle Y aufgerufen wird, ist diese Methode Z zu rufen." Beachten Sie, dass die Mapping-Zielmethode, obwohl sie in C# nicht unterstützt wird, möglicherweise einen anderen Namen als der Name der Schnittstellenmethode hat! (VB unterstützt dies ausdrücklich, glaube ich.)

In Ihrem Fall haben Sie drei Methoden und jede der drei Methoden entspricht einer Methode in einer der beteiligten Schnittstellen.

Wenn der Compiler einen Aufruf an eine virtuelle Methode über eine Schnittstelle ausgibt, sagt die generierte IL etwa "IFoo.Bar für dieses Objekt aufrufen" - und IFoo.Bar wird dann mithilfe der Schnittstellenkarte aufgelöst.

Sie müssen es manchmal verwenden, wenn Sie entweder Signaturen haben, die sich nur im Rückgabetyp unterscheiden, oder wenn Sie zwei heterogene Schnittstellen implementieren, die denselben Methodennamen haben, aber unterschiedliche Dinge tun sollten. Wo auch immer Sie können es aber vermeiden, tun! Es macht sehr verwirrenden Code.