2012-05-04 25 views
12

私はクラスAとクラスBの両方にいくつかのプロパティがあります。それ自身の特性を持つ別のクラスCもあります。インターフェイスと複数継承C#

私はクラスCのインスタンスを作成するたびに、objClassCを使用して3つのクラスすべてのすべてのプロパティにアクセスしたいと思います。

これをC#でどのように達成できますか?

私は2つの問題が直面メートル: - 私はインターフェイスの代わりに、クラスAを使用する場合、私は、クラスC(C#は多重継承をサポートしていません)

  • にクラスA、Bの両方を継承することはできません

    1. を、B(インタフェースでは、我々はフィールドが含まれていません)
  • +3

    コンポジションを使用できます。また、[ミックスイン](http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –

    答えて

    29

    なぜあなたは、あなたが

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

    チェックアウトの記事Composition vs Inheritance

    EDITにアクセスすることができますComposition

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

    クラスC.使用の内側に、クラスAとクラスBのインスタンスが含まれていません。

    インターフェイスinsteを使用する場合クラスA、Bの広告

    まあ、インタフェースは、フィールドを含めることはできませんあなたは1を定義する場合は、コンパイルエラーになります(私たちはCANインタフェースではありません はフィールドが含まれています)。ただし、インターフェイスのすべての要素がpublicと見なされるため、access specifiersを指定できないという点を除いて、インターフェイスにはプロパティを含めることができます。

    :後で、としてそれらを使用することができ

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

    :次に、あなたのようなクラスCでそれらを実装することができ

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

    :あなたはとインターフェース「A」と「B」のプロパティを定義することができます

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

    +1継承上の組成のため –

    +2

    @downvoter、注意してほしい – Habib

    +0

    しかし、クラスCでIA、IBの実装が必要な場合は、IAとIBを実装する必要がありますか?私たちはインターフェイスを実装せずにプロパティを定義するだけです...? –

    2

    インタフェースのプロパティが含まれていてもよい、すなわち:

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

    インターフェイスは多重継承の欠如に対する解決策ではありません。彼らはちょうど同じことをしません。あなたが得ることができるのは、CをAのサブクラスにして、B型のプロパティを持つことです。 A、B、Cが何をすべきか教えてください。

    4

    インターフェイスはプロパティを持つことができますが、メソッドを使用したい場合は、合成または依存の注入が必要な場合があります。

    Interface A 
    { 
        int PropA {get; set;} 
    } 
    
    
    Interface B 
    { 
        int PropB {get; set;} 
    } 
    
    class C : A, B 
    { 
    
    } 
    

    //

    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

    インタフェースがフィールドを含めることはできませんが、彼らはプロパティを含めることができ、いくつかの方法でこれらの文を置きます。ほとんどの場合、プロパティは、フィールドのように使うことができ、そしてそこに言うと全く困難ではありません:タイプICombinedPropertiesの保存場所を考えると

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

    は、1が直接、大騒ぎせずにすべての4つのプロパティにアクセスすることができます。

    ただし、プロパティでは実行できないフィールドで実行できることがいくつかあることに注意してください。たとえば、フィールドをInterlocked.Incrementに渡すことはできますが、プロパティはできません。変数にコピーしてInterlocked.Incrementを呼び出すことによってプロパティをInterlocked.Incrementにしようとしましたが、その結果をプロパティにコピーすることがある場合がありますが、2つのスレッドが同時に同じことをしようとすると失敗します。例えば2つのスレッドが最初に5に等しいフィールドにInterlocked.Incrementを呼び出すと、7を生成することが保証されるのに対して、両方のスレッドが5の値を読み込み、6にインクリメントしてから6に書き戻すことができます。

    これを回避するには、フィールドにインターロックされたメソッドを実行するメソッドが必要です(フィールドにInterlocked.Incrementを呼び出して結果を返す関数など)。インタフェースのインスタンスを考えるとrefパラメータ(例えば

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

    としてフィールドで指定したデリゲートを呼び出す関数を含む、1のような何かを行うことができます:

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

    かを、 1はローカル変数maskValuexorValueを持っていたし、アトミック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); 
    ); 
    

    1はフィールド上で実行したいアクションの唯一の少数の種類があった場合、それは単に含めることが最も簡単でしょうそれらをインタフェース内に置く。一方、上記のアプローチは、インターフェースがフィールドを公開し、クライアントが任意の一連のアクションを実行できるようにします。

    +0

    -1。問題に対処していない。 – radarbob

    +0

    @radarbob:質問の一部は、インターフェイスにフィールドが含まれていないという事実と関係していました。他の答えは、多くの場合、フィールドの代わりにプロパティを使用する可能性があることを認めています。プロパティを受け入れられる代替物ではない方法でフィールドを使用したい場合でも、インターフェイスを使用することが可能であるという事実を増幅したいと考えました。 – supercat

    1

    継承副構成を使用しているときに、プロパティがクライアントと異なる方法でどのように公開されるかを検討します。

    継承:

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

    組成: - 良いこと

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

    継承クリーナーAPIを提供します。

    構成では、クラスの内部構造について何かを知る必要があります。そのような良いことではありません。これは、最小知識の原則としてよく知られているlaw of demeterに違反します。これを回避するには、Bclass & Aclassプロパティを1対1で公開/返すCclassプロパティを用意しておき、Bclass & Aclass参照は、Cclassでプライベートまたは保護されます。そして、CclassはA & Bに依存しているのではなく、公開されていないものを公開していないことを明らかにしました。

    @AlejoBrzに同意しますが、ここではインターフェイスが適切ではありません。

    私はまた、「相続財産よりも組成を好む」とうなずく。しかし、これはガイドラインであり、困難で迅速なルールではありません。

    関連する問題