web-dev-qa-db-ja.com

C#アクセスできないタイプを組み合わせる方法は?

私は別のライブラリーの助けを借りてライブラリーを開発しています。

したがって、ここで設定したのは、追加機能のためにライブラリのクラスをサブクラス化する2つのクラスです。問題は、クラスを別のクラスで交換して使用できるようにしたいときに発生します。 how sad am i したがって、「スーパークラス」タイプである限り、コンストラクタを介してこれらのグラフィックスをオブジェクトに渡すことができるようにしたいと考えています。問題は、RectangleとCircleの位置を設定するためのプロパティ名が異なり、オブジェクト内で位置を設定する必要があることです。タイプをチェックしてからキャストすることもできますが、誰かが三角形のようなグラフィックを渡したい場合は、クラスを編集してタイプの三角形をチェックする必要があります。

代わりに、CenterXプロパティとCenterYプロパティを必要とする円と四角形のクラスが実装するICenterableインターフェイスを作成することを選択しました。これで、ICenterableオブジェクトを持っている人はだれでも、それをオブジェクトに渡すことができます。これは完璧ですが、渡されるパラメーターがICenterable型か「スーパークラス」型かを選択する必要があります。ここでも、特定の機能が必要なときにキャストできますが、たとえば、「スーパークラス」が渡されてICenterableが実装されていない場合はどうなりますか。コンストラクターで、両方のタイプであることを確認するか、エラーをスローするかを確認できますが、それはずさんなようです。

最良の解決策は、渡されるオブジェクトがICenterableを実装し、「スーパークラス」を拡張する必要があると私が述べることができる場合です。私は両方を行うクラスを作成することでこれを行いますが、CircleとRectangleを拡張する必要があるため、私のサークルと四角形のクラスはそのクラスを拡張できません。 enter image description here やればいけないほど、悪くなります。私はそれが私が望むようにならないことを受け入れ、インターフェイスを忘れて、それが長方形であるか、円であるかを確認し、必要に応じて後でさらに追加する必要がありますか?それとももっと良い方法がありますか?

ありがとう

4
TheJesBoy

継承する代わりに、ラッピングしてみてください。制約を指定できるように、汎用ラッパーを使用してください。

interface IWrapper
{
    void Center();
}

interface IWrapper<T> : IWrapper where T : Superclass
{
    T AsOriginalItem();
}

abstract class WrapperBase<T> : IWrapper<T>
{
    protected readonly T _wrappedItem;

    public WrapperBase(T wrappedItem)
    {
        _wrappedItem = wrappedItem;
    }

    abstract public Center();

    public T AsOriginalItem()
    {
        return _wrappedItem;
    }        
}

class RectangleWrapper : WrapperBase<Rectangle>
{
    public RectangleWrapper(Rectangle item) : base(item) {}

    public override void Center()
    {
        var originalRectangle = this.AsOriginalItem();
        originalRectangle.MoveTo(etc....);
    }
}


class CircleWrapper : WrapperBase<Circle>
{
    public CircleWrapper(Circle item) : base(item) {}

    public override void Center()
    {
        var originalCircle = this.AsOriginalItem();
        originalCircle.MoveTo(etc....);
    }
}

ここで、たとえばFooのコンストラクターに形状を渡したい場合、次のようにします。

class Foo
{
    public Foo(IWrapper wrapper)
    {
        wrapper.Center();
    }
}

var foo1 = new Foo(new RectangleWrapper(originalRectangle));
var foo2 = new Foo(new CircleWrapper(originalCircle));

...そしてあなたはタイプセーフです。

5
John Wu

私がこれを正しく理解している場合、投稿されたケースはあなたが直面している問題のほんの一部partです。 CircleRectangleが位置を設定するための異なるメソッドを持っている場合、Superclassが抽象化しているものは何ですか(これは、Shapeの線に沿っていると思います)?

特定のユースケースで、CircleRectangleの実装がすでに異なる場合、Superclass型は実際には役に立ちません(つまり、すべての実装で必要な単一のプロパティ/メソッドを定義していません)。 John Wuが助言したように、型を再定義し、それらの外部ライブラリ型(形状)を独自の型の拡張としてラップすることを検討する必要があります。このようにして、すべての形状に必要なプロパティ/メソッドの独自の均一なセットを定義できます。

2
Vector Zita