C#抽象方法只用基类实现?

时间:2010-09-15 14:27:18

标签: c# architecture inheritance oop

考虑以下问题:

你有一个类'A',它可以作为许多其他类似类的基类,例如。一个名为B的课程。

A类在自身中很有用(并且已经在整个地方使用过),因此不是抽象的。

关键是你现在希望强制执行一个新协议,要求所有继承自A(包括A本身)的类实现一个方法'func()'。如果子类忘记实现func(),则应该存在编译器错误。

class A {
  A func() { ret new A(...) }
}

class B : A {
  A func() { ret new B(...) }
}

class C : A {
  // Should give error : no func()
}

问题是否清楚?我不能创建A :: func()抽象,因为我希望能够继续使用A作为具体类。我无法使其成为虚拟,因为这会导致子类回退到超类(而不是给编译器错误)。

接近解决方案的唯一方法是创建一个新的抽象类A *并使所有自定义类型继承自该类,并将A的所有当前用法替换为具有从A继承的新类“DefaultA”的具体类。 *。这看起来很乱。请告诉我还有其他方法可以做到这一点吗?

6 个答案:

答案 0 :(得分:10)

如果子类型不覆盖特定方法,则根本无法保持A具体类型并强制编译器错误。

答案 1 :(得分:2)

好吧,正如你所说,你可以创建一个继承自A的中间抽象类X,并要求派生类继承自X。 X然后声明一个带有签名匹配{{}的受保护抽象方法。 1}}并覆盖A中的func以调用该方法。这是一个例子:

func

这种方法的主要问题是要求所有派生类现在继承自X而不是A.所以你刚刚将执行问题从一种更改为另一种。

在我看来,更简洁的做法是将class A { public virtual A func() { ... } } abstract class X : A { protected abstract A funcImpl(); public override A func() { return funcImpl(); } } class B : X { /* must now implement funcImpl() to avoid compiler error */ } class C : X { /* must now implement funcImpl() to avoid compiler error */ } 重构为基类A,并在那里ABase抽象。然后密封func并要求AB继承C而不是ABase

A

您必须将class ABase { public abstract ABase func(); } sealed class A : ABase { public override ABase func() { ... } } class B : ABase { // forced to override func() public override ABase func() { ... } } 的所有用法替换为A - 但Visual Studio中有一些出色的重构工具(以及ReSharper等第三方工具),这使得它比以前更少痛苦是

答案 2 :(得分:1)

如果这是你需要做的,那么是的。

在我看来,您可能希望重新考虑这一要求。我经常实现类似的框架,在子类中强制实现是一个聪明的伎俩。然后我发现,作为这些框架的使用者,我会重复代码或默认为一些无法实现(如空方法)。这些都不是理想的,因为它们会增加杂乱和噪音,并降低可维护性。

此外,如果此模式的应用程序是自行工作(即您的示例具有返回其自身实例的子类),那么您可能希望尝试不同的东西,例如正确的工厂模式。呃,“尝试”我的意思是利用一个控制容器的反转,如Castle Windsor,Ninject,Unity。

答案 3 :(得分:1)

如果A类是抽象的,则无法实例化它。因此,

new A();

abstract A func(); // within the A class definition

是矛盾的。

如果你避开抽象,而转向虚拟,你可以得到 运行时 (不是编译时)检查:

// In the A class definition.
protected virtual A func()
{
    if (GetType() != typeof(A))
        throw // ...
}

答案 4 :(得分:1)

基本上,你要我们“让这个突破,但不要让这个突破。”也许你看到了固有的冲突。

这就是为什么基类只应该用作基类而不能单独使用的原因之一。

答案 5 :(得分:0)

这可能更麻烦,但您可能会强制B,C,D等实现需要func()的接口。然后确保它们总是通过工厂方法构建。所以有点像:

public class B: A, IFunc{
   private B(){}
   public static B Create(){ return new B(); }

}