繁体   English   中英

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

[英]C# abstract method with base class only implementation?

请考虑以下问题:

你有一个类'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”的具体类。 这看起来很乱。 请告诉我还有其他方法可以做到这一点吗?

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

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

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 */ }

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

在我看来,更ABase方法是将A重构为基类ABase并在那里使用func 然后密封A并要求BC继承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() { ... }
}

你必须用ABase替换A所有用途 - 但是在Visual Studio中有一些优秀的重构工具(以及像ReSharper这样的第三方工具),这使得它比以前更加痛苦。

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

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

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

如果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 // ...
}

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

这是基类只应用作基类,而不是自己使用的原因之一。

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

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

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM