2012-05-04 16 views
12

Ich habe eine Reihe von Klasse A und Klasse B beide haben einige Eigenschaften. und eine andere Klasse C, die ihre eigenen Eigenschaften hat.Schnittstelle vs Mehrfachvererbung in C#

Immer wenn ich eine Instanz der Klasse C erstelle, möchte ich mit objClassC auf alle Eigenschaften aller drei Klassen zugreifen.

Wie kann ich das in C# erreichen?

Ich bin vor zwei Problemen: -

  1. ich nicht sowohl die Klassen A, B in der Klasse C (C# unterstützt keine Mehrfachvererbung) erben kann
  2. wenn i-Schnittstelle anstelle der Klasse A , B (In-Schnittstelle können wir Enthält Felder nicht)
+3

Sie können Zusammensetzung verwenden. Es gibt auch [Mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –

Antwort

29

Warum Sie enthalten keine Instanz der Klasse A und der Klasse B innerhalb der Klasse C. Verwendung Composition

class C 
{ 
//class C properties 
public A objA{get;set;} 
public B objeB{get;set;} 
} 

Dann können Sie den Artikel

C objc = new C(); 
objc.objA.Property1 = "something"; 
objc.objB.Property1 = "something from b"; 

Check-out Zugang Composition vs Inheritance

EDIT:

wenn ich Interface inste verwende Anzeige der Klasse A, B (In-Schnittstelle können wir nicht enthält Felder)

Nun, Schnittstellen können Felder nicht enthalten, wenn Sie eine definieren, werden Sie Kompilierungsfehler erhalten. Schnittstellen können jedoch Eigenschaften enthalten, mit der Ausnahme, dass Sie access specifiers nicht angeben können, da alle Elemente der Schnittstelle als public gelten. Sie können Eigenschaften für Interface 'A' definieren und 'B' wie:

public class C : IA, IB 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 
} 

Später können Sie sie als verwenden:

public interface IA 
{ 
    int Property1 { get; set; } 
} 


public interface IB 
{ 
    int Property2 { get; set; } 
} 

Dann können Sie sie in der Klasse C wie implementieren können

C objC = new C(); 
objC.Property1 = 0; 
objC.Property1 = 0; 
+4

+1 für Komposition der Vererbung –

+2

@downvoter, Pflege – Habib

+0

Kommentar Aber Wenn die Implementierung von IA, IB in Klasse C erforderlich ist, was muss IA und IB implementieren? Wir können nur Eigenschaften definieren, ohne Schnittstellen zu implementieren ...? –

2

Schnittstellen Eigenschaften enthalten, dh .:

public interface IFoo 
{ 
    string Bar { get; set; } 
} 
3

Schnittstellen sind keine Lösung für das Fehlen von Mehrfachvererbung. Sie machen einfach nicht die gleichen Dinge. Der nächste, den Sie bekommen können, ist, dass C eine Unterklasse von A ist und eine Eigenschaft des Typs B hat. Vielleicht, wenn Sie uns sagen, was A, B und C tun sollten, können wir eine Antwort geben, die Ihren Bedürfnissen besser entspricht ...

4

Schnittstellen können Eigenschaften haben, aber wenn Sie auch die Methoden verwenden möchten, ist möglicherweise die Zusammensetzung oder Abhängigkeitsinjektion erforderlich.

Interface A 
{ 
    int PropA {get; set;} 
} 


Interface B 
{ 
    int PropB {get; set;} 
} 

class C : A, B 
{ 

} 

// diese Aussage in irgendeiner Methode setzen

C c = new C(); 
c.PropA = 1; 
c.PropB = 2; 
1
public interface IAA 
{ 
    string NameOfA { get; set; } 
} 
public class AA : IAA 
{ 
    public string NameOfA{get;set;} 
} 

public interface IBB 
{ 
    string NameOfB { get; set; } 
}  
public class BB : IBB 
{ 
    public string NameOfB{get;set;} 
} 

public class CC : IAA, IBB 
{ 
    private IAA a; 
    private IBB b;    

    public CC() 
    { 
     a = new AA{ NameOfA="a"}; 
     b = new BB{ NameOfB="b"}; 
    } 

    public string NameOfA{ 
     get{ 
      return this.a.NameOfA; 
      } 
     set{ 
      this.a.NameOfA = value; 
      } 
    } 

    public string NameOfB 
    { 
     get{ 
      return this.b.NameOfB; 
     } 
     set{ 
      this.b.NameOfB = value; 
     } 
    } 
} 
1

Schnittstellen können Felder nicht enthalten, aber sie können Eigenschaften enthalten. In den meisten Fällen können Eigenschaften wie Felder verwendet werden, und es gibt keine Probleme mit den Worten:

 
interface ISomeProperties 
    {int prop1 {get;set;}; string prop2 {get; set;}} 
interface IMoreProperties 
    {string prop3 {get;set;}; double prop4 {get; set;}} 
interface ICombinedProperties : ISomeProperties, IMoreProperties; 
    { } 

ein Lagerort des Typs Gegeben ICombinedProperties kann man alle vier Eigenschaften direkt und ohne viel Aufhebens zugreifen.

Es sollte jedoch beachtet werden, dass es einige Dinge gibt, die mit Feldern gemacht werden können, die mit Eigenschaften nicht gemacht werden können. Zum Beispiel, während ein Feld an Interlocked.Increment übergeben werden kann, kann eine Eigenschaft nicht; Versuch, Interlocked.Increment eine Eigenschaft durch Kopieren in eine Variable, Aufruf Interlocked.Increment auf, und dann das Ergebnis in die Eigenschaft zurück kopieren "funktioniert" in einigen Fällen, würde aber fehlschlagen, wenn zwei Threads versuchten, das gleiche Ding gleichzeitig (es würde tun möglich sein, zB für beide Threads, einen Wert von 5 zu lesen, ihn auf 6 zu erhöhen und dann 6 zurückzuschreiben, während zwei Threads den Aufruf Interlocked.Increment auf einem Feld haben, das anfänglich gleich 5 war, würde garantiert 7 ergeben.

Um dies zu umgehen, kann es notwendig sein, dass die Schnittstelle einige Methoden enthält, die eine verblockte Methode für ein Feld ausführen (z. B. könnte eine Funktion Interlocked.Increment auf dem Feld aufrufen und das Ergebnis zurückgeben) und/oder beinhalten Funktionen, die einen bestimmten Delegierten mit einem Feld als ref Parameter (zB

 
delegate void ActionByRef<T1>(ref T1 p1); 
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2); 
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3); 
interface IThing 
{ // Must allow client code to work directly with a field of type T. 
    void ActOnThing(ActionByRef<T> proc); 
    void ActOnThing<ExtraT1>(ActionByRef<T, ExtraT1> proc, ref ExtraT1 ExtraP1); 
    void ActOnThing<ExtraT1, ExtraT2> 
     (ActionByRef<T> proc, ref ExtraT1 ExtraP1, ref ExtraT2 ExtraP2); 
} 

Gegeben eine Instanz der Schnittstelle aufrufen wird, ein etwas wie tun könnte:

 
    theInstance.ActOnThing(
    (ref int param) => Threading.Interlocked.Increment(ref param) 
); 

oder, wenn man lokale Variablen hatte maskValue und xorValue und wollte atomar, um das Feld aktualisieren mit field = (field & maskValue)^xorValue:

 
    theInstance.ActOnThing(
    (ref int Param, ref int MaskValue, ref int XorValue) => { 
     int oldValue,newValue; 
     do {oldValue = param; newValue = (oldValue & MaskValue)^XorValue; 
     while (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue) != 
      oldValue), 
    ref maskValue, ref xorValue); 
); 

Wenn es nur wenige Arten von Aktionen wäre, würde man auf den Feldern ausführen wollen, wäre es am einfachsten sein, einfach schließen sie innerhalb der Schnittstelle. Auf der anderen Seite erlaubt der oben gegebene Ansatz einer Schnittstelle, ihre Felder so zu exponieren, dass Clients willkürliche Abfolgen von Aktionen auf ihnen ausführen können.

+0

-1. geht nicht auf die Frage ein. – radarbob

+0

@radarbob: Ein Teil der Frage hatte mit der Tatsache zu tun, dass Schnittstellen keine Felder enthalten können. Andere Antworten bestätigten, dass man in vielen Fällen Eigenschaften anstelle von Feldern verwenden kann. Ich wollte die Tatsache verstärken, dass es möglich ist, Interfaces auch dann zu verwenden, wenn man Felder so einsetzen möchte, dass Eigenschaften keine akzeptablen Alternativen darstellen. – supercat

1

Berücksichtigen Sie, wie die Eigenschaften beim Vererben der Vizezusammensetzung anders dargestellt werden als beim Client.

Vererbung:

 
    var myCclass = new Cclass; 
    myClass.propertyA; 
    myClass.propertyB; 
    myClass.propertyC; 
    // and so on 

Zusammensetzung:

var myCclass = new Cclass; 
    myCclass.bClass.propertyB; 
    myCclass.aClass.propertyA; 
    myCclass.propertyC; 

Vererbung gibt eine sauberere API - eine gute Sache.

Zusammensetzung erfordert, dass ich etwas über die interne Struktur der Klasse weiß - nicht so eine gute Sache. Dies verletzt die law of demeter - besser bekannt als das Prinzip des geringsten Wissens.Sie können dies umgehen, indem Sie Cclass-Eigenschaften verwenden, die die Bclass & Aclass-Eigenschaften eins-zu-eins offen legen und zurückgeben - und Ihre Bclass & Aclass-Referenzen wären dann privat oder in Cclass geschützt. AND Cclass hat die totale Kontrolle darüber, was exponiert ist, anstatt auf A & B zu verzichten, um nicht öffentlich zugängliche Sachen zu haben, die Sie nicht kennengelernt haben.

ich mit @AlejoBrz zustimmen, Schnittstellen ist hier nicht angebracht.

Ich nenne auch "bevorzugen Zusammensetzung über Vererbung." Aber das ist eine Richtlinie, keine feste Regel.