2014-06-30 8 views
16

Dies könnte eine einfache/grundlegende OOP Frage sein, aber ich kann immer noch nicht herausfinden, wie man es löst. Ich hatte während eines Interviews folgendes Problem: Erstellen Sie ein UML-Klassendiagramm und schreiben Sie den Basiscode für ein "Smart" -Telefon, das die Funktionen eines Telefons und eines MP3-Players enthält. Wir haben mit der folgenden (angenommen) Lösung bekommt:C# OOP Zusammensetzung und Generalisierung zur gleichen Zeit

class Telephone 
{ 
    public string name { get; set; } 

    public Telephone() 
    { 
     name = "name telephone"; 
    } 
} 

class MP3 
{ 
    public string name { get; set; } 

    public MP3() 
    { 
     name = "name mp3"; 
    } 
} 

Und die „intelligente“ Telefon Klasse:

class TelephoneMP3 
{ 
    public Telephone tel; 
    public MP3 mp3; 

    public TelephoneMP3() 
    { 
     tel = new Telephone(); 
     mp3 = new MP3(); 
    } 
} 

Wie Sie sehen können, haben wir eine Zusammensetzung Beziehung zwischen dem TelephoneMP3 haben und das Telefon/MP3-Klassen.

Aber mit diesem Code ist das TelephoneMP3 kein Telefon und das TelephoneMP3 ist auch kein MP3, was nicht logisch ist. Also, welche Änderungen sollte ich machen, um dies gültig zu machen? Zum Beispiel diese Art von Test:

  1. Telefon/MP3/TelephoneMP3 bleiben muss Klassen (alle drei von ihnen)
  2. ich konnte:

    if (telMp3 is Telephone) 
    { 
        Console.WriteLine("TelephoneMP3 is telephone"); 
    }   
    if (telMp3 is MP3) 
    { 
        Console.WriteLine("TelephoneMP3 is mp3"); 
    } 
    

    Die Änderungen mit den folgenden Ausführungen werden könnten gemacht bei Bedarf Schnittstellen/andere Klassen hinzufügen

  3. TelephoneMP3 darf nicht alle Funktionalitäten von einem Telefon/MP3 duplizieren (zum Beispiel während einer Vererbung von einer Schnittstelle, an der das TelephoneMP3 verpflichtet ist, den Code von allen Schnittstellen m zu schreiben) Glut)

Vielen Dank im Voraus

+2

Was genau wollen Sie erreichen? Möchtest du, dass 'TelephoneMP3' auf 'ist MP3' und'ist Telefon' zurück? –

+0

Ja, das ist das Ziel – IonR

+0

Raten Sie Am Ende möchten Sie, dass TelephoneMp3 entweder Mp3 oder ein Telefon ist, aber nicht beides? – Rangesh

Antwort

-5

C# keine Mehrfachvererbung nicht unterstützt, müssen Sie Schnittstellen und abstrakte Klasse für gemeinsame Implementierungen verwenden, können Sie die follwing tun:

Edit: Ich habe hinzufügen mehr Details zu meiner Antwort

abstract class BaseDevice 
{ 
    public string name { get; set; } 

    public void Print() 
    { 
     Console.WriteLine("{0}", name); 
    } 
} 

public interface IPhone 
{ 
    void DoPhone(); 
} 


public interface IMP3 
{ 
    void DoMP3(); 
} 

class Telephone :BaseDevice , IPhone 
{ 
    public Telephone() 
    { 
      name = "name telephone"; 
    } 
} 

class MP3 : BaseDevice , IMP3 
{ 
     public MP3() 
     { 
      name = "name mp3"; 
     } 
} 

class telMp3 : BaseDevice , IMP3, IPhone 
{ 
    private Telephone _tel; 
    private MP3 _mp3; 

    public telMp3() 
     { 
      name = "name telMp3"; 
     } 
    public void DoPhone() 
    { 
     _tel.DoPhone(); 
    } 
    public void DoMP3() 
    { 
     _mp3.DoMP3(); 
    } 


} 
+2

Vielen Dank, aber ich bin mir nicht ganz sicher, denn in diesem Fall haben wir ein Telefon ist ein MP3, und ein MP3 ist ein Telefon, das sollte nicht wahr sein ... – IonR

+21

Wie Ist diese Antwort akzeptabel? Telefon und Mp3 haben eine gemeinsame Basisklasse, die eine Namenseigenschaft hat, wie ist diese richtige Vererbung? Mp3 und Telefon stammen nicht von demselben Elternteil. Einer ist ein 'Telefon' und einer ist ein' Spieler'. Sowohl IMp3 als auch IPhone sind leere Schnittstellen, nur um den "Ist" -Test zu bestehen. Ich würde diese Antwort in einem Bewerbungsgespräch definitiv nicht akzeptieren. –

+2

_in telMp3 Aufrufe an IMP3 sollten an _mp3 weitergeleitet werden, und Anrufe an IPhone sollten an _tel_ weitergeleitet werden. Wie ist das genau? –

35

Da C# keine Mehrfachvererbung nicht unterstützt, betrachten Schnittstellen statt:

public interface Phone{ ... } 
public interface Mp3{ ... } 

public class Telephone : Phone{ ... } 
public class Mp3Player : Mp3{ ... } 
public class Smartphone : Phone, Mp3{ ... } 

Auf diese Weise ist Smartphone sowohl Phone als auch Mp3. Wenn Sie eine Methode schreiben müssen, die auf einem Telephone funktioniert, verwenden Sie stattdessen die Schnittstelle Phone. Auf diese Weise können Sie entweder Telephone oder Smartphone als Argument übergeben.

+19

Beachten Sie, dass ein gemeinsamer Benennungsstandard in C# für Schnittstellen das Präfix "I" verwendet. – Default

+0

Das OP fragt: 'TelefonMP3 darf nicht alle Funktionalitäten von einem Telefon/MP3 duplizieren (ich nehme an, dass er/sie den Code dupliziert). C# erlaubt nur die Vererbung von einer Basisklasse, daher muss das Smartphone eine interne Instanz von MP3-Player oder ein Telefon (oder beides) enthalten. – Ben

+27

@Default, aber es gibt rechtliche Konsequenzen mit einem 'IPhone'. ;) – paqogomez

2

Wie über diese Lösung:

public interface ITelephone 
{ 
    string Name{get;} 
    void MakeCall(); 
} 

public interface IMp3 
{ 
    string Name { get; } 
    void Play(string filename); 
} 

public abstract class BaseTelephone : ITelephone 
{ 
    public virtual string Name { get { return "Telephone"; } } 

    void MakeCall() 
    { 
     // code to make a call. 
    } 
} 

public class MyMp3Player : IMp3 
{ 
    public string Name { get { return "Mp3 Player"; } } 

    public void Play(string filename) 
    { 
     // code to play an mp3 file. 
    } 
} 

public class SmartPhone : BaseTelephone, IMp3 
{ 
    public override string Name { get { return "SmartPhone"; } } 

    private IMp3 Player { get { return _Player; } set { _Player = value; } } 
    private IMp3 _Player = new MyMp3Player(); 

    public void Play(string filename) { Player.Play(filename); } 
} 

diese Weise wird das Smartphone auch einen MP3-Player sein kann, aber intern hat es einen MP3-Player, die es verwendet, die Musik zu spielen. Der interne Player kann durch Verwendung der SmartPhone-Eigenschaft Player gegen eine neue ausgetauscht werden (z. B. Upgrade).

Der Code für das Telefon wird nur einmal in der Basistelefonklasse geschrieben. Der Code für den MP3-Player wird nur einmal auch geschrieben - in der MyMp3Player-Klasse.

+0

Sie haben zwei 'Name' String-Eigenschaften. Dies wird nicht kompiliert, Sie müssen es mit dem Schlüsselwort 'new' überschreiben. –

+0

@YuvalItzchakov Es kompiliert, aber es gab eine Warnung. Ich habe das dank Yuval behoben. – Ben

5

Sie können auch explicit interface implemenations verwenden, um die Verwendung der gemeinsamen Variablen Name zu begrenzen.Auf diese Weise müssten Sie in die Benutzeroberfläche wechseln, um darauf zuzugreifen. Sie können weiterhin öffentliche Eigenschaften/Methoden von der Schnittstelle haben.

Zusammensetzung wird noch verwendet, aber die SmartPhone hat Kontrolle über die Implementierungen ihrer Eigenschaften/Methoden.

Für mich wäre dies die einfachste Implementierung mit zu arbeiten, weil ich selten sowohl die Implementierung aus dem mp3player und dem Telefon verwenden möchte, sondern eher eine davon. Außerdem habe ich immer noch die volle Kontrolle darüber, was passiert, wenn die Schnittstellenmethoden auf der SmartPhone aufgerufen werden.

class User 
{ 
    void UseSmartPhone(SmartPhone smartPhone) 
    { 
     // Cannot access private property 'Name' here 
     Console.WriteLine(smartPhone.Name); 

     // Cannot access explicit implementation of 'IMp3Player.Play' 
     smartPhone.Play(); 

     // You can send the phone to the method that accepts an IMp3Player though 
     PlaySong(smartPhone); 

     // This works fine. You are sure to get the Phone name here. 
     Console.WriteLine(((IPhone)smartPhone).Name); 

     // This works fine, since the Call is public in SmartPhone. 
     smartPhone.Call(); 
    } 

    void CallSomeone(IPhone phone) 
    { 
     phone.Call(); 
    } 

    void PlaySong(IMp3Player player) 
    { 
     player.Play(); 
    } 
} 

class SmartPhone : IPhone, IMp3Player 
{ 
    private Phone mPhone; 
    private Mp3Player mMp3Player; 

    public SmartPhone() 
    { 
     mPhone = new Phone(); 
     mMp3Player = new Mp3Player(); 
    } 

    public void Call() 
    { 
     mPhone.Call(); 
    } 

    string IPhone.Name 
    { 
     get { return mPhone.Name; } 
    } 

    string IMp3Player.Name 
    { 
     get { return mMp3Player.Name; } 
    } 

    void IMp3Player.Play() 
    { 
     mMp3Player.Play(); 
    } 
} 

class Mp3Player 
{ 
    public string Name { get; set; } 

    public void Play() 
    { 
    } 
} 

class Phone 
{ 
    public string Name { get; set; } 

    public void Call() 
    { 
    } 
} 

interface IPhone 
{ 
    string Name { get; } 
    void Call(); 
} 

interface IMp3Player 
{ 
    string Name { get; } 
    void Play(); 
} 
17

Es ist fast ähnlich wie die anderen Antworten, aber ..
Ich denke, es ist die beste Genauigkeit in Bezug auf die Vererbungshierarchie hat.

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var telephone = new Telephone(); 
     Console.WriteLine(telephone.Name); 
     telephone.OutboundCall("+1 234 567"); 
     Console.WriteLine("Am I a Telephone?     {0}", telephone is Telephone); 
     Console.WriteLine("Am I a MP3?      {0}", telephone is MediaPlayer3); 
     Console.WriteLine("Am I a Smartphone?    {0}", telephone is Smartphone); 
     Console.WriteLine("Do I Have Telephone Capabilities? {0}", telephone is ITelephone); 
     Console.WriteLine("Do I Have MP3 Capabilities?  {0}", telephone is IMediaPlayer3); 
     Console.WriteLine(); 

     var mp3 = new MediaPlayer3(); 
     Console.WriteLine(mp3.Name); 
     mp3.PlaySong("Lalala"); 
     Console.WriteLine("Am I a Telephone?     {0}", mp3 is Telephone); 
     Console.WriteLine("Am I a MP3?      {0}", mp3 is MediaPlayer3); 
     Console.WriteLine("Am I a Smartphone?    {0}", mp3 is Smartphone); 
     Console.WriteLine("Do I Have Telephone Capabilities? {0}", mp3 is ITelephone); 
     Console.WriteLine("Do I Have MP3 Capabilities?  {0}", mp3 is IMediaPlayer3); 
     Console.WriteLine(); 

     var smartphone = new Smartphone(); 
     Console.WriteLine(smartphone.Name); 
     smartphone.OutboundCall("+1 234 567"); 
     smartphone.PlaySong("Lalala"); 
     Console.WriteLine("Am I a Telephone?     {0}", smartphone is Telephone); 
     Console.WriteLine("Am I a MP3?      {0}", smartphone is MediaPlayer3); 
     Console.WriteLine("Am I a Smartphone?    {0}", smartphone is Smartphone); 
     Console.WriteLine("Do I Have Telephone Capabilities? {0}", smartphone is ITelephone); 
     Console.WriteLine("Do I Have MP3 Capabilities?  {0}", smartphone is IMediaPlayer3); 

     Console.ReadKey(); 
    } 

    public interface IDevice 
    { 
     string Name { get; } 
    } 

    public interface ITelephone : IDevice 
    { 
     void OutboundCall(string number); 
    } 

    public interface IMediaPlayer3 : IDevice 
    { 
     void PlaySong(string filename); 
    } 


    public class Telephone : ITelephone 
    { 
     public string Name { get { return "Telephone"; } } 

     public void OutboundCall(string number) 
     { 
      Console.WriteLine("Calling {0}", number); 
     } 
    } 

    public class MediaPlayer3 : IMediaPlayer3 
    { 
     public string Name { get { return "MP3"; } } 

     public void PlaySong(string filename) 
     { 
      Console.WriteLine("Playing Song {0}", filename); 
     } 
    } 

    public class Smartphone : ITelephone, IMediaPlayer3 
    { 
     private readonly Telephone telephone; 
     private readonly MediaPlayer3 mp3; 

     public Smartphone() 
     { 
      telephone = new Telephone(); 
      mp3 = new MediaPlayer3(); 
     } 

     public string Name { get { return "Smartphone"; } } 

     public void OutboundCall(string number) 
     { 
      telephone.OutboundCall(number); 
     } 

     public void PlaySong(string filename) 
     { 
      mp3.PlaySong(filename); 
     } 
    } 

} 

Programm Ausgabe:

 
Telephone 
Calling +1 234 567 
Am I a Telephone?     True 
Am I a MP3?      False 
AM I a Smartphone?    False 
Do I Have Telephone Capabilities? True 
Do I Have MP3 Capabilities?  False 

MP3 
Playing Song Lalala 
Am I a Telephone?     False 
Am I a MP3?      True 
AM I a Smartphone?    False 
Do I Have Telephone Capabilities? False 
Do I Have MP3 Capabilities?  True 

Smartphone 
Calling +1 234 567 
Playing Song Lalala 
Am I a Telephone?     False 
Am I a MP3?      False 
AM I a Smartphone?    True 
Do I Have Telephone Capabilities? True 
Do I Have MP3 Capabilities?  True 
2

Verwenden Sie die strategy pattern (einige Abkürzungen unten verwendet, werden Sie den Kern erhalten).

public class Device { 

    private List<App> apps; 

    public Device() { 

    this.apps = new List<App>(); 

    this.apps.Add(new Mp3Player()); 
    this.apps.Add(new Telephone()); 

    } 

} 

public class Mp3Player implements App {...} 
public class Telephone implements App {...} 
public interface App {...} 

Haftungsausschluss: meine Muttersprache ist PHP, vergib mir alle nicht C# Coding-Standards etc etc.

6

Ich denke, diese Frage Interview ist nicht (wie sollten alle Interviewfragen sein) über die Herausforderung selbst. Die Kodierung des Zusammenfügens zweier Klassen über Komposition könnte mit einem Lehrbuch beantwortet werden. Diese Herausforderung ist eine subtile Trickfrage, und ich schlage vor, dass der Punkt darin besteht, Sie dazu zu bringen, warum zu diskutieren. Zumindest würde ich von meinen Interviewpartnern verlangen.


Dieser Test:

if(telMp3 is Telephone && telMp3 is MP3) { 

... ist das eigentliche Problem. Warum müssen Sie diese Kriterien erfüllen? Dieser Test macht den Zweck, Objekte aus der Zusammensetzung zu bauen, vollständig ungültig. Es verlangt, dass die Objekte auf eine bestimmte Art und Weise implementiert werden. Es zeigt, dass die vorhandenen Klassenimplementierungen bereits eng mit der Codebasis gekoppelt sind (wenn sie nicht beseitigt werden können). Diese Anforderungen bedeuten, dass SOLID principles nicht gefolgt wurden, weil Sie nicht nur die Methoden eines Basistyps erfüllen können, müssen Sie tatsächlich der Basistyp sein. Das ist nicht gut.


Wie andere Antworten gesagt haben, wäre die Lösung die Verwendung von Schnittstellen. Dann können Sie Ihr Objekt an jede Methode übergeben, die die Schnittstelle erfordert. Diese Art der Nutzung wäre ein Test wie erfordern so:

if (telMp3 is IPhone && telMp3 is IMp3) { 

... aber man kann das nicht tun, wegen der Begrenzung Ihrer Herausforderung. Das bedeutet, dass Leute im Rest des Codes Methoden geschrieben haben, die explizit von den spezifischen Typen Telephone und MP3 abhängen. Das ist das eigentliche Problem.


Meiner Meinung nach ist die richtige Antwort auf diese Herausforderung zu sagen, dass die Codebasis den Test nicht besteht.Der spezifische Fallout in Ihrer Herausforderung ist irrelevant; Sie müssen die Anforderungen der Herausforderung ändern, bevor Sie sie ordnungsgemäß lösen können. Ein Befragter, der diese Tatsache erkennt, würde den Test mit Bravour bestehen.

1

Sie versuchen, eine Produkthierarchie zu modellieren, in der ein bestimmtes Produkt seine eigenen spezifischen Eigenschaften haben kann und aus Standard-Unterprodukten besteht. Dies ist in der Tat ein Beispiel für das Zusammensetzungsmuster. Ich empfehle, eine Basisschnittstelle für jede Produktkomponente einzuführen und dann spezifische Schnittstellen für Telefon-, MP3-Player- und Smartphone-Produkte zu schaffen. Im traditionellen Kompositionsmuster kann jeder Knoten eine willkürliche Liste von Komponenten enthalten, zu denen Unterkomponenten hinzugefügt oder entfernt werden können. In Ihrem Datenmodell erscheint es jedoch sinnvoller, für jeden spezifischen Produkttyp seine genauen untergeordneten Elemente anzugeben und dann anzugeben eine generische Methode, um über sie zu iterieren. Dies ermöglicht, dass spezifische (Teil-) Komponenten eines bestimmten Typs/Interface in der gesamten Produkthierarchie leicht abfragbar sein können.

Ich habe auch eine Schnittstelle für ein GPS-Produkt eingeführt, da alle neuen Telefone eingebaute GPS-Empfänger enthalten - nur um zu zeigen, wie man mit rekursiven Hierarchien von Komponenten arbeitet.

public interface IProductComponent 
{ 
    string Name { get; set; } 

    IEnumerable<IProductComponent> ChildComponents { get; } 

    IEnumerable<IProductComponent> WalkAllComponents { get; } 

    TProductComponent UniqueProductComponent<TProductComponent>() where TProductComponent : class, IProductComponent; 
} 

public interface ITelephone : IProductComponent 
{ 
    IGps Gps { get; } 
} 

public interface IMp3Player : IProductComponent 
{ 
} 


public interface IGps : IProductComponent 
{ 
    double AltitudeAccuracy { get; } 
} 

public interface ISmartPhone : IProductComponent 
{ 
    ITelephone Telephone { get; } 

    IMp3Player Mp3Player { get; } 
} 

Diese Schnittstellen können dann durch einen parallelen Satz von Klassen implementiert werden:

public abstract class ProductComponentBase : IProductComponent 
{ 
    string name; 

    protected ProductComponentBase(string name) 
    { 
     this.name = name; 
    } 

    #region IProductComponent Members 

    public string Name 
    { 
     get 
     { 
      return name; 
     } 
     set 
     { 
      name = value; 
     } 
    } 

    public virtual IEnumerable<IProductComponent> ChildComponents 
    { 
     get 
     { 
      return Enumerable.Empty<IProductComponent>(); 
     } 
    } 

    public IEnumerable<IProductComponent> WalkAllComponents 
    { 
     get 
     { 
      yield return this; 
      foreach (var child in ChildComponents) 
      { 
       foreach (var subChild in child.WalkAllComponents) 
        yield return subChild; 
      } 
     } 
    } 

    public TProductComponent UniqueProductComponent<TProductComponent>() where TProductComponent : class, IProductComponent 
    { 
     TProductComponent foundComponent = null; 
     foreach (var child in WalkAllComponents.OfType<TProductComponent>()) 
     { 
      if (foundComponent == null) 
       foundComponent = child; 
      else 
       throw new Exception("Duplicate products found of type " + typeof(TProductComponent).Name); 
     } 
     return foundComponent; 
    } 

    #endregion 
} 

public class Telephone : ProductComponentBase, ITelephone 
{ 
    IGps gps = new Gps(); 

    public Telephone() 
     : base("telephone") 
    { 
    } 

    #region ITelephone Members 

    public IGps Gps 
    { 
     get 
     { 
      return gps; 
     } 
    } 

    #endregion 

    IEnumerable<IProductComponent> BaseChildComponents 
    { 
     get 
     { 
      return base.ChildComponents; 
     } 
    } 

    public override IEnumerable<IProductComponent> ChildComponents 
    { 
     get 
     { 
      if (Gps != null) 
       yield return Gps; 
      foreach (var child in BaseChildComponents) 
       yield return child; 
     } 
    } 
} 

public class Gps : ProductComponentBase, IGps 
{ 
    public Gps() 
     : base("gps") 
    { 
    } 

    #region IGps Members 

    public double AltitudeAccuracy 
    { 
     get { return 100.0; } 
    } 

    #endregion 
} 

public class TelephoneMP3 : ProductComponentBase, ISmartPhone 
{ 
    ITelephone telephone; 
    IMp3Player mp3Player; 

    public TelephoneMP3() 
     : base("TelephoneMP3") 
    { 
     this.telephone = new Telephone(); 
     this.mp3Player = new MP3(); 
    } 

    IEnumerable<IProductComponent> BaseChildComponents 
    { 
     get 
     { 
      return base.ChildComponents; 
     } 
    } 

    public override IEnumerable<IProductComponent> ChildComponents 
    { 
     get 
     { 
      if (Telephone != null) 
       yield return Telephone; 
      if (Mp3Player != null) 
       yield return Mp3Player; 
      foreach (var child in BaseChildComponents) 
       yield return child; 

     } 
    } 

    #region ISmartPhone Members 

    public ITelephone Telephone 
    { 
     get { return telephone; } 
    } 

    public IMp3Player Mp3Player 
    { 
     get { return mp3Player; } 
    } 

    #endregion 
} 

public class MP3 : ProductComponentBase, IMp3Player 
{ 
    public MP3() 
     : base("mp3Player") 
    { 
    } 
} 

Als neue Produktkomponententypen (oder Unterklasse) hinzugefügt werden, sie die „ChildComponents“ ihrer Eltern außer Kraft setzen und Rückkehr ihre domänenspezifischen Kinder.

Anschließend können Sie (rekursiv) die Produkthierarchie nach Komponenten eines bestimmten Typs für Ihre Verwendung abfragen. Zum Beispiel:

var accuracy = smartPhone.UniqueProductComponent<IGps>().AltitudeAccuracy 

oder

bool hasPhone = (component.UniqueProductComponent<ITelephone>() != null) 

Diese Kombination von Verallgemeinerung und Zusammensetzung vermeidet Code duplizieren, während explizite machen die Art der Unterkomponenten, die in einem bestimmten Produkt gefunden werden sollte. Außerdem wird vermieden, dass alle übergeordneten Produkte die Schnittstellen ihrer Standard-Kinder übernehmen und alle Anrufe an sie weiterleiten.

17

Hier gibt es einige gute Antworten. Die Antworten, die sagen, dass Schnittstellen zu verwenden sind, sind gut, und das ist, was der Interviewer wahrscheinlich sucht. Ich würde jedoch in Betracht ziehen, einfach die Prämisse zu leugnen, dass die Beziehung "ist-eine-Art" zufriedenstellend ist, ist eine gute Idee. Vielmehr würde ich mit einer Dienstleister Organisation betrachten:

public interface ITelephone { ... } 
internal class MyTelephone : ITelephone { ... } 
public interface IMusicPlayer { ... } 
internal class MyPlayer : IMusicPlayer { ... } 
public interface IServiceProvider 
{ 
    T QueryService<T>() where T : class; 
} 

internal class MyDevice : IServiceProvider 
{ 
    MyTelephone phone = new MyTelephone(); 
    MyPlayer player = new MyPlayer(); 
    public T QueryService<T>() where T : class 
    { 
     if (typeof(T) == typeof(ITelephone)) return (T)(object)phone; 
     if (typeof(T) == typeof(IPlayer)) return (T)(object)player; 
     return null; 
    } 
} 

Jetzt hat ein Anrufer ein MyDevice in der Hand über seine IServiceProvider Schnittstelle. Sie fragen es

ITelephone phone = myDevice.QueryService<ITelephone>(); 

und wenn phone nicht-null ist, dann kann das Gerät wie ein Telefon handeln. Aber

myDevice is ITelephone 

ist falsch. Das Gerät ist nicht ein Telefon, es weiß, wie Sie etwas finden, das wie ein Telefon fungiert.

Für mehr in diesem Sinne, studieren Plug-in-Architekturen wie MAF.

+2

Wer wusste, das iPhone war heimlich ein COM-Objekt die ganze Zeit ... – dlev

+0

Warum ist Query-Service generisch? – adrianm

+0

@adrianm: Was würdest du bevorzugen? –

2

könnten Sie implizites Casting verwenden

class TelephoneMP3 
{ 
    public Telephone tel; 
    public MP3 mp3; 

    public TelephoneMP3() 
    { 
     tel = new Telephone(); 
     mp3 = new MP3(); 
    } 

    public static implicit operator Telephone(TelephoneMP3 telemp3) { 
     return telemp3.tel; 
    } 

    public static implicit operator MP3(TelephoneMP3 telemp3) { 
     return telemp3.mp3; 
    } 

} 

Es wird nicht die genaue Prüfung bestehen, die Sie vorgeschlagen, aber Sie können

var teleMp3 = new TelephoneMP3(); 
Telephone t = teleMp3; 
+0

+1 Obwohl die Tatsache, dass der Operator is nicht funktioniert, die Nützlichkeit dieser Lösung einschränkt. – Taemyr

1

Im Gegensatz zu allen anderen Antworten tun bin ich sehr zuversichtlich, dass die Wie diese Frage gestellt wird, macht es unmöglich. Der Grund dafür ist der folgende:

Sie explizit

angeben Aber mit diesem Code, der TelephoneMP3 ist kein Telefon und die TelephoneMP3 ist kein MP3 entweder, was nicht logisch ist. Also, welche Änderungen sollte ich machen, um dies gültig zu machen?

Das Wort "ist" lässt mich sofort an den Operator "ist" denken. Ich nehme sofort an, dass du das wirklich willst.

Sie dann später gehen zu sagen, die folgenden:

Telefon/MP3/TelephoneMP3 Klassen bleiben muss (alle 3 von ihnen)

Nun sicher, dass wir folgendes tun:

interface ITelephone { } 
class Telephone 
{ 
    public string name { get; set; } 

    public Telephone() 
    { 
     name = "name telephone"; 
    } 
} 
interface IMP3 { } 

class MP3 : IMP3 
{ 
    public string name { get; set; } 

    public MP3() 
    { 
     name = "name mp3"; 
    } 
} 

class TelephoneMP3 : ITelephone, IMP3 
{ 
    public Telephone tel; 
    public MP3 mp3; 

    public TelephoneMP3() 
    { 
     tel = new Telephone(); 
     mp3 = new MP3(); 
    } 
} 

Aber wir haben immer noch ein Problem. Das Wort ist". Da wir die Klassen TelefonMP3, Telefon und MP3 und C# nicht mehrfach vererben lassen müssen, ist das einfach nicht möglich.

mein Punkt zu illustrieren:

public class Program 
{ 
    static void Main(string[] args) 
    { 
     TelephoneMP3 t = new TelephoneMP3(); 
     Console.WriteLine((t is TelephoneMP3)? true:false); 
     Console.WriteLine((t is ITelephone) ? true : false); 
     Console.WriteLine((t is IMP3) ? true : false); 
     Console.WriteLine((t is Telephone) ? true : false); 
     Console.WriteLine((t is MP3) ? true : false); 
     Console.ReadLine(); 
    } 
} 

Diese Sie

Wahre

Wahre

Wahre

Falsch

geben Falsch

Mit anderen Worten TelephoneMP3 "ist" ein ITelephone. TelefonMP3 "ist" ein IMP3; Es ist jedoch nicht möglich, dass ein TelephoneMP3 sowohl MP3 als auch Telefon ist.