是否有某种方法可以将抽象类型定义为抽象方法中的参数,并且当该方法在派生类中实现时,您会更改方法的类型以接受派生类型?
代码:
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
}
}
在我看来,这是有道理的。一个抽象类表明有一个派生类必须实现的方法,但是它们可以改变作为参数传入的对象的类型,只要它来自同一个继承链…
我最终做的是,从抽象类中删除抽象方法AddProducts
,而只是在派生类中实现它,但是将来其他类没有契约,它们必须创建自己的AddProducts
实现。感觉不对。
我希望这是有意义的。如果这是一个重复的问题,我很抱歉,但我通过搜索找不到任何东西。
谢谢,
bgs264
您可以将您的A
类设为泛型,并在您的addProducts
方法中使用泛型参数:
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)
{
}
}
不,这是不可能的:假设您在类A
的变量上调用addProducts
,该变量指向类C
的实例,传递的对象是ProductBase
,但不是的某个产品
。传递的实例无法转换为的某个产品
,这就是为什么它不会首先编译。
最接近这一点的是泛型解决方案:
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);
}
当然,这意味着您必须将任何类型为A
的变量键入一些产品
,如A
如果不指定T
类型参数的实际值,您就不能只拥有A
类型的变量(提供addProducts
方法)。另一方面,如上所述,在您的解决方案中调用该addProducts
方法也是不可能的。
您现在可以引入一个非强类型方法:
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.");
}
}
}
但是,只有当类的某些用户可以知道泛型类型而其他用户不知道时,通常才真正需要这样的解决方案。
坦率地说,对于实现代码,我只会使用演员阵容。我唯一能让它“漂亮”的时候是它是否影响了公共调用者:
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
和覆盖
在同一级别,但一个解决方法是使用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;
// ...
}
}