6

抽象型を抽象メソッドのパラメーターとして定義する方法はありますか?そのメソッドが派生クラスに実装されている場合、派生型を受け入れるようにメソッドの型を変更しますか?

コード:

public abstract class ProductBase
{
}

public class SomeProduct
    : ProductBase
{

}

public abstract class A
{
    protected abstract void addProduct(ProductBase p);
}

// This works
public class B : A
{        
    protected override void addProduct(ProductBase p)
    {
        // Do some work
    }
}

// This is what I'd like to do
public class C : A
{
    // Compiler error here because I have accepted a SomeProduct and not a ProductBase
    protected override void addProduct(SomeProduct p)
    {
        // Do some work on the specialisation - I can use the SomeProduct directly
    }
}

私の頭の中では、それはある種の意味を持っています。派生クラスが実装する必要があるメソッドがあることを示す抽象クラスですが、同じ継承チェーンからのものである限り、パラメーターとして渡されるオブジェクトの型を変更できます...

私がやったことはAddProduct、抽象クラスから抽象メソッドを削除し、代わりに派生クラスでそれを実装することですが、将来、他のクラスが独自の実装を作成する必要があるという契約はありませんAddProduct. そして、それは正しくありません。

これが理にかなっていることを願っています。これが重複した質問である場合は申し訳ありませんが、検索しても何も見つかりませんでした。

ありがとう、
bgs264

4

3 に答える 3

10

クラスをジェネリックにして、メソッドAでジェネリック引数を使用できます。addProduct

public abstract class A<TProduct> where TProduct : ProductBase 
{
    protected abstract void addProduct(TProduct p);
}

public class B : A<ProductBase>
{        
    protected override void addProduct(ProductBase p)
    {
    }
}

public class C : A<SomeProduct>
{
    protected override void addProduct(SomeProduct p)
    {
    }
}
于 2012-06-13T12:58:53.000 に答える
2

いいえ、それは不可能です。 classのインスタンスを指すaddProductclass の変数を呼び出して、 ではなく であるオブジェクトを渡しているとします。渡されたインスタンスを に変換できませんでした。これが、そもそもコンパイルされない理由です。ACProductBaseSomeProductSomeProduct

これに最も近いのは、ジェネリックを使用したソリューションです。

public abstract class A<T>
    where T : ProductBase
{
    protected abstract void addProduct(T p);

}

次に、クラス C を次のように定義できます。

public class C : A<SomeProduct>
{
    protected override void addProduct(SomeProduct p);
}

もちろん、これは のように to 型の変数を入力する必要があることを意味ASomeProductますA<SomeProduct> = new C();

型引数の実際の値を指定せずにA、(メソッドを提供する)型の変数だけを持つことはできなくなりました。一方、上記で概説したように、そのメソッドを呼び出すことも、ソリューションでは不可能でした。addProductTaddProduct

ここで、強く型付けされていないメソッドを導入できます。

public abstract class A<T>
    where T : ProductBase
{
    protected abstract void addProduct(T p);

    protected void addProductUntyped(ProductBase p)
    {
        T typedProduct = p as ProductBase;
        if (typedProduct != null) {
            addProduct(typedProduct);
        } else {
            throw new ArgumentException("p has an incompatible type.");
        }
    }
}

ただし、通常、このような解決策が実際に必要になるのは、クラスの一部のユーザーがジェネリック型を認識でき、他のユーザーが認識できない場合のみです。

于 2012-06-13T12:58:02.943 に答える
1

率直に言って、実装コードについては、私はただキャストと一緒に住んでいたでしょう。私がこれを「きれい」にするのは、それが一般の発信者に影響を与えた場合だけです。

protected override void addProduct(ProductBase p)
{
    SomeProduct prod = (SomeProduct)p;
    // ...
}

私があまり好きではない1つのオプションは、ジェネリックです。

public abstract class A<T> where T : ProductBase
{
    protected abstract void addProduct(T p);
}

public class C : A<SomeProduct>
{
    protected override void addProduct(SomeProduct p)
    {
        // ...
    }
}

私がこれを嫌う理由は、非ジェネリックを使用することができなくAなったため、多くの抽象化が失われるためです。もう1つのオプションはnew、パラメーターを再宣言するメソッドです。残念ながら、同じレベルで行うことはできませんが、回避策は2つの方法を使用することnewです。override

public abstract class A
{
    protected void addProduct(ProductBase p) { addProductImpl(p);}
    protected abstract void addProductImpl(ProductBase p);
}

public class C : A
{
    new protected void addProduct(SomeProduct p) { addProductImpl(p);}
    protected override void addProductImpl(ProductBase p)
    {
        SomeProduct prod = (SomeProduct) p;
        // ...
    }
}
于 2012-06-13T13:00:21.877 に答える