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 实例的 classaddProduct变量,并传递一个是 a 的对象,但不是 a 。传递的实例无法转换为,这就是为什么这首先不会编译。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);
}

当然,这意味着您必须键入任何类型的变量Ato SomeProduct,如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;
    // ...
}

我自己不太喜欢的一种选择是泛型:

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,所以你失去了很多抽象。另一种选择是new重新声明参数的方法。new不幸的是,您不能override在同一级别,但解决方法是使用 2 种方法:

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 回答