提问者:小点点

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


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

代码:

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


共3个答案

匿名用户

您可以将您的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;
        // ...
    }
}