实现抽象方法时更改参数类型

时间:2012-06-13 12:47:29

标签: c# inheritance abstract-class

是否有某种方法可以将抽象类型定义为抽象方法中的参数,并且在派生类中实现该方法时,可以更改方法的类型以接受派生类型?

代码:

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

3 个答案:

答案 0 :(得分:6)

您可以将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)
    {
    }
}

答案 1 :(得分:1)

不,这是不可能的:假设您在类addProduct的变量上调用A,该变量指向类C的实例,并传递一个{{1}的对象1}},但不是ProductBase。传递的实例无法转换为SomeProduct,这就是为什么它不会在第一时间编译。

最接近这一点的是具有泛型的解决方案:

SomeProduct

然后,您可以像这样定义C类:

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类型的任何变量,就像在SomeProduct中一样。

在不指定A<SomeProduct> = new C();类型参数的实际值的情况下,您不能只拥有类型A的变量(提供addProduct方法)。另一方面,如上所述,在您的解决方案中也不可能调用T方法。

可能现在引入非强类型方法:

addProduct

然而,这种解决方案通常只在该类的某些用户可以知道泛型类型而其他用户不知道时才需要。

答案 2 :(得分: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方法重新声明参数。不幸的是,您不能newoverride处于同一级别,但解决方法是使用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;
        // ...
    }
}