4

それで、皆さんがこれについてどう思うか聞いてみたいです。

3つの異なる継承パスがすべて別の基本クラスを実装する必要があるプロジェクトがあります。これは多重継承であり、C#では許可されていません。コードを重複させずにこれを実装する方法に興味があります。

編集:私は3つのクラスを所有していません。3つのクラスは、サードパーティのコードからのものです。したがって、それらすべてに基本クラスを拡張させることはできません。

現在、私は3つの異なるクラスを使用しており、それぞれが異なる基本クラスを拡張しています。次に、3つの抽象クラスのそれぞれに同じコードがあります。

単一のインターフェースを使用することもできますが、それでもコードを複製する必要があります。

コードを実装するある種の静的クラスを作成し、それを3つの抽象クラスのそれぞれで参照することができます。重複をなくすことができますが、どう思うかわかりません。インターフェイスにExtensionsメソッドを実装することはできますが、インターフェイス自体が空になり、拡張メソッド(重複コードを含む)がまったく異なるファイルに含まれるため、正しくないようです。さらに、拡張メソッドにプロパティを実装できません...

ここでコードの重複をどのように除外できますか?

編集、継承ツリー:

class Class1 : 3rdPartyBaseClass1 { }
class Class2 : 3rdPartyBaseClass2 { }
class Class3 : 3rdPartyBaseClass3 { }

上記の各クラスに入れたいコードがありますが、3rdPartyClassesに追加できません。

4

5 に答える 5

6

Class1、Class2、およびClass3が実装できるインターフェースを作成します。次に、コードを拡張メソッドに入れて、すべてに適用されるようにします。

interface IMyInterface {
    void Foo();   //these are the methods that these 
        //classes actually have in common
    void Bar();    
}

public class Class1 : 3rdPartyBaseClass1, IMyInterface {
    // whatever

}

public static class IMyInterfaceExtensions {
    public static void CommonMethod(this IMyInterface obj) {
        obj.Foo();
        obj.Bar();
    }
}

public static class Program {
    public static void Main() {
        var instance = new Class1();
        instance.CommonMethod();
    }
}
于 2009-09-27T02:44:20.420 に答える
5

OK、私の以前の提案に似たことができます。また、再帰の提案にも似ています。3 つすべての派生クラスで必要な機能については、そのインターフェイスを実装する (そして呼び出しごとに実行する実際のコードを持つ) 単一のクラス (キックのために「実装者」と呼びます) と共に単一のインターフェイスを作成できます。 )。

次に、各派生クラスで Interface を実装し、Implementerのプライベート インスタンスを作成します。各インターフェイス メソッドでは、Implementer のプライベート インスタンスに呼び出しを渡すだけです。実装者とその派生クラスはすべてインターフェイスを実装するため、インターフェイスに変更を加えると、それに応じて実装者と派生クラスを変更する必要があります。

そして、Implementer のプライベート インスタンスに呼び出しを渡すすべての行を除いて、すべてのコードは 1 か所にあります (明らかに、複数の継承はこれよりも優れていますが、あなたが望む軍隊ではなく、あなたが持っている軍隊と戦争に行きます持っていた)。

更新: クラスのパブリック インスタンスを各派生クラスに追加するだけではどうですか?

public class DerivedClass1 : ThirdPartyClass1
{
    public MyClass myClass = new MyClass();
}

または、デメテルが誰であるかを気にし、LOC で支払いを受ける場合:

public class DerivedClass1 : ThirdPartyClass1
{
    private MyClass _myClass = new MyClass();
    public MyClass myClass
    {
        get
        {
            return _myClass;
        }
    }
}

次に、次のように MyClass メソッドを呼び出すだけです。

DerivedClass1 dc1 = new DerivedClass1();
dc1.myClass.DoSomething();

この方法で、私たちは皆眠りにつくことができました。

于 2009-09-27T03:24:55.610 に答える
4

MusiGenesis の提案と同様に、サードパーティ クラスの機能が必要であるが、それらから派生する必要がない場合、次のようにコンポジションを使用できます。

class ThirdPartyBaseClass1
{
    public void DoOne() {}
}

class ThirdPartyBaseClass2
{
    public void DoTwo() { }
}

class ThirdPartyBaseClass3
{
    public void DoThree() { }
}

abstract class Base
{
    public void DoAll() { }
}

class Class1 : Base
{
    public void DoOne() { _doer.DoOne(); }
    private readonly ThirdPartyBaseClass1 _doer = new ThirdPartyBaseClass1();
}

class Class2 : Base
{
    public void DoTwo() { _doer.DoTwo(); }
    private readonly ThirdPartyBaseClass2 _doer = new ThirdPartyBaseClass2();
}

class Class3 : Base
{
    public void DoThree() { _doer.DoThree(); }
    private readonly ThirdPartyBaseClass3 _doer = new ThirdPartyBaseClass3();
}

これにより、必要なインターフェイスを自由に定義して、クラスに実装することもできます。

于 2009-09-27T03:53:00.270 に答える
1

これらの3つのパスが一緒になった時点で、新しい抽象クラスを継承ツリーに挿入する必要があるように思えますが、実際には十分な情報がありません。継承ツリーの一部を投稿できれば、それは大いに役立ちます。

于 2009-09-27T02:30:19.747 に答える
1

継承の代わりに構成を使用したい場合があると思います。これを行う正確な方法は、サードパーティのクラスがどのように見えるか、および独自のコードがどのように見えるかによって異なります。問題に関連するより具体的なコードが役立ちますが、たとえば、独自の初期化コードですべてカスタマイズする必要がある 3 つの異なるサードパーティ GUI ウィジェットが必要だとします。

ケース 1:サード パーティのウィジェットが次のようになっているとします。

public interface IThirdPartyWidget {
  public void doWidgetStuff();
}

public class ThirdPartyWidget1: ThirdyPartyWidget implements IThirdPartyWidget {
 ...
}

public class ThirdPartyWidget2: ThirdPartyWidget implements IThirdPartyWidget {
 ...
}

できるよ:

public class MyWidget implements IThirdPartyWidget {
 private IThirdPartyWidget delegateWidget;
 public MyWidget(IThirdPartyWidget delegateWidget) {
  this.delegateWidget = delegateWidget;
 }

 public void doWidgetStuff() {
  delegateWidget.doWidgetStuff();
 }
}

ケース 2:これらのウィジェットを拡張する必要があり、独自のコードをリファクタリングする必要があるとします。

public class MyWidget1: ThirdPartyWidget1 {
 public void myMethod() {
  runMyCode();
 }

 private void runMyCode() {
  //something complicated happens
 }
}

public class MyWidget2: ThirdPartyWidget2 {
 public void myMethod() {
  runMyCode();
 }

 private void runMyCode() {
  //something complicated happens
 }
}

これは次のようになります。

public class MyCodeRunner {
 public void runMyCode() {
  //...
 }
}

public class MyWidget1: ThirdPartyWidget1 {
 private MyCodeRunner myCode = new MyCodeRunner();
 public void myMethod() {
  myCode .runMyCode();
 }
}

public class MyWidget2: ThirdPartyWidget2 {
 private MyCodeRunner myCode = new MyCodeRunner();
 public void myMethod() {
  myCode .runMyCode();
 }
}

これが理にかなっていることを願っています!

于 2009-09-27T04:13:06.877 に答える