12

クラス A とクラス B のセットがあり、どちらもいくつかのプロパティを持っています。独自のプロパティを持つ別のクラス C。

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

C#でこれを達成するにはどうすればよいですか?

私は2つの問題に直面しています:-

  1. クラス C でクラス A、B の両方を継承できません (C# は多重継承をサポートしていません)。
  2. クラスA、Bの代わりにインターフェイスを使用する場合(インターフェイスでは、フィールドを含めることはできません)
4

7 に答える 7

29

クラス C 内にクラス A とクラス B のインスタンスを含めてみませんか。コンポジションを使用します。

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

その後、アクセスできます

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

構成と継承の記事をチェックしてください

編集:

クラスA、Bの代わりにインターフェイスを使用する場合(インターフェイスでは、フィールドを含めることはできません)

インターフェイスにフィールドを含めることはできません。フィールドを定義すると、コンパイル エラーが発生します。ただし、インターフェイスのすべての要素が考慮されるため、アクセス指定子を指定できないことを除いて、インターフェイスにはプロパティを含めることができますpublic。インターフェイス 'A' および 'B' のプロパティを次のように定義できます。

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


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

次に、次のようにクラス C でそれらを実装できます。

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

後でそれらを次のように使用できます。

C objC = new C();
objC.Property1 = 0;
objC.Property1 = 0;
于 2012-05-04T11:12:06.957 に答える
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;
于 2012-05-04T11:14:35.207 に答える
3

インターフェイスは、多重継承の欠如に対する解決策ではありません。彼らは同じことをしていないだけです。あなたが得ることができる最も近いものは、C を A のサブクラスにし、型 B のプロパティを持たせることです。おそらく、A、B、C が何をすべきかを教えていただければ、ニーズにより適した答えを提供できます...

于 2012-05-04T11:13:37.937 に答える
2

インターフェイスには、次のようなプロパティが含まれる場合があります。

public interface IFoo
{
    string Bar { get; set; }
}
于 2012-05-04T11:10:11.060 に答える
2

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

継承:

    var myCclass = 新しい Cclass;
    myClass.propertyA;
    myClass.propertyB;
    myClass.propertyC;
    // 等々

構成:

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

継承により、よりクリーンな API が提供されます。これは良いことです。

コンポジションでは、クラスの内部構造についてある程度知っている必要がありますが、これはあまり良いことではありません。これは、最小知識の原則としてよく知られているデメテルの法則に違反しています。これを回避するには、Bclass と Aclass のプロパティを 1 対 1 で公開/返す Cclass プロパティを使用します。Bclass と Aclass の参照は、Cclass で非公開または保護されます。そして Cclass は、公開されていないものを公開しないように A & B に依存するのではなく、公開されるものを完全に制御します。

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

また、「継承よりも構成を優先する」ことに同意します。ただし、これはガイドラインであり、厳格な規則ではありません。

于 2012-08-10T03:05:49.717 に答える
1

インターフェイスにフィールドを含めることはできませんが、プロパティを含めることはできます。ほとんどの場合、プロパティはフィールドのように使用できます。次のように言うのは難しくありません。

インターフェイス ISomeProperties
  {int prop1 {get;set;}; 文字列 prop2 {get; 設定;}}
インターフェイス IMoreProperties
  {string prop3 {get;set;}; double prop4 {get; 設定;}}
インターフェイス ICombinedProperties : ISomeProperties、IMoreProperties;
  { }

type の保存場所が与えられたICombinedProperties場合、4 つのプロパティすべてに直接、手間をかけずにアクセスできます。

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

これを回避するには、インターフェイスに、フィールドでインターロックされたメソッドを実行するいくつかのメソッドを含める必要がある場合があります (たとえば、Interlocked.Incrementフィールドで呼び出して結果を返す関数を含めることができます)。refパラメータとしてフィールドを持つ指定されたデリゲート(例:

デリゲート void ActionByRef<T1>(ref T1 p1);
デリゲート void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
デリゲート void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
インターフェイス IThing
{ // クライアント コードが 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);
}

インターフェースのインスタンスが与えられると、次のようなことができます:

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

または、ローカル変数がmaskValueありxorValue、フィールドをアトミ​​ックに更新したい場合field = (field & maskValue) ^ xorValue:

  theInstance.ActOnThing(
    (ref int パラメータ、ref int MaskValue、ref int XorValue) => {
        int oldValue,newValue;
        do {oldValue = param; newValue = (oldValue & MaskValue) ^ XorValue;
        while (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue) !=
          古い値)、
    ref maskValue、ref xorValue);
  );

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

于 2012-08-06T15:38:44.863 に答える
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;
        }
    }
}
于 2012-05-04T11:18:32.043 に答える