11

我有抽象基类,其中包含一些字段和一些作用于这些字段的方法。例如:

public abstract class A
{
    protected double _field;

    public double SquaredField { get { return _field * _field; } }

    ... some other abstract methods
}

我想在其构造函数中强制 A 的所有子项初始化 _field

public class B : A
{
    public B(double field)
    {
         _field = Math.Sqrt(field);
    }

    ... some other method implementations
}

实现这一目标的正确模式是什么?

- 编辑

我最终做的是:

public abstract class A
{
    protected readonly double _field;

    public A(double field)
    {
         _field = field;
    }

    public double SquaredField { get { return _field * _field; } }

    ... some other abstract methods
}


public class B : A
{
    public B(double field) : base(field)
    {
    }

    public static B CreateNew(double val)
    {
         return new B(Math.Sqrt(field));
    }

    ... some other method implementations
}
4

4 回答 4

13

根本不要向派生类公开字段。相反,创建一个受保护的抽象属性

public abstract class A
{
    protected double Field { get; }

    public double SquaredField { get { return Field * Field; } }
}

或者,如果该字段对于特定实例应该始终是常量,则将其设为构造函数参数并保持私有:

public abstract class A
{
    private readonly double _field;

    public double SquaredField { get { return _field * _field; } }

    protected A(double field)
    {
        _field = field;
    }
}
于 2012-08-15T14:18:40.297 回答
3

不要让类A有一个无参数的构造函数:

public abstract class A
{
    protected double _field;

    public double SquaredField { get { return _field * _field; } }

    // Require any fields that must be initialized in the base class's
    // constructor. If there are a lot of such fields, consider encapsulating
    // them all in their own class, e.g. AArgs.
    protected A(double field)
    {
        _field = field;
    }
}

public class B : A
{
    // You must call a base class constructor as below, because class A
    // no longer has a parameterless constructor to use by default.
    public B(double field)
        : base(field)
    {
    }
}

附录

如果您不能在构造函数中进行初始化,则可以将字段设置为抽象属性:

public abstract class A
{
    protected abstract double Field { get; }

    public double SquaredField { get { return Field * Field; } }
}

现在,派生类必须实现该属性,因此您将为依赖SquaredField属性做好准备。不过我会更改名称,因为它们不再是字段。

于 2012-08-15T14:19:19.293 回答
2

这可能是一个信号,表明字段组比A自身更紧密耦合,因此应该将其移动到一个类中,例如AParams.

然后A你可以声明一个abstract protected AParams createParams()方法。

于 2012-08-15T14:33:16.383 回答
1

您可以使用单独的抽象函数来完成此操作。子类将被迫实现它。

public abstract class A
{
    protected double _field;

    protected A()
    {
        InitializeField();
    }

    protected abstract void InitializeField();

    public double SquaredField { get { return _field * _field; } }
}

public class B : A
{
    protected override void InitializeField()
    {
        // Initialize...
    }
}
于 2012-08-15T14:26:08.740 回答