基类中的抽象属性,强制程序员对其进行定义


10

我正在使用嵌入式设备的状态模式进行编码。我有一个称为State的基类/抽象类,然后每个离散(具体)状态类都实现了抽象State类。

在状态类中,我有几种抽象方法。如果我不在离散(具体)类中实现抽象方法,Visual Studio将给出如下错误:

...错误1'myConcreteState'未实现继承的抽象成员'myAbstractState'

现在:我正在尝试为每个名为StateName的州创建String属性。每当创建新的具体类时,都需要定义StateName。如果不使用VS,我希望VS抛出错误。有没有简单的方法可以做到这一点?

我已经在抽象/基类中尝试过此操作:

public abstract string StateName { get; set; }

但是我不需要在每个州中实现Get和Set方法。

修订的问题:在理想情况下,将要求每个状态类都具有StateName定义并从抽象基类继承。

StateName = "MyState1"; //or whatever the state's name is

如果缺少该语句,则Visual Studio将生成如上所述的错误。这可能吗?如果可以,怎么办?


2
我不明白这个问题。
Ben Aaronson

我猜想做到这一点的“正确”方法是在基类上有一个受保护的构造函数,该构造函数需要状态名称作为参数。
罗曼·赖纳

@RomanReiner我也考虑过这样做..但它似乎多余,因为每次更改/调用状态时,我都必须输入名称。
GisMofx

@BenAaronson我已经在底部澄清了我的问题。
GisMofx

状态名称是每个类型常量还是每个实例常量?
Roman Reiner

Answers:


16

我猜想做到这一点的“正确”方法是在基类上有一个受保护的构造函数,该构造函数需要状态名称作为参数。

public abstract class State
{
    private readonly string _name;

    protected State(string name)
    {
        if(String.IsNullOrEmpty(name))
            throw new ArgumentException("Must not be empty", "name");

        _name = name;
    }

    public string Name { get { return _name; } }
}

然后,具体状态提供一个公共构造函数,该构造函数以适当的名称隐式调用基类构造函数。

public abstract class SomeState : State
{
    public SomeState() : base("The name of this state")
    {
        // ...
    }
}

由于基类不公开任何其他构造函数(既不是受保护的也不是公共的),每个继承的类都需要通过该单个构造函数,因此需要定义一个名称。

请注意,在实例化具体状态时无需提供名称,因为它的构造函数会处理该情况:

var someState = new SomeState(); // No need to define the name here
var name = someState.Name; // returns "The name of this state"

1
谢谢!实际上,我的基类构造函数现在需要一个附加参数。所以我有两个输入。设置完成后,立即收到错误,我需要在状态类构造函数中添加一个附加参数...:base(arg1, arg2)!这是我一直在寻找的解决方案。这确实有助于保持我的州代码更一致。
GisMofx 2015年

3

从C#6(我相信-C#:新的和改进的C#6.0)开始,您可以创建仅吸气剂属性。因此,您可以像这样声明您的基类-

public abstract class State
{
    public abstract string name { get; }

    // Your other functions....
}

然后在子类中,您可以State像这样实现:

public class SomeState : State
{
    public override string name { get { return "State_1"; } }
}

甚至使用lambda运算符更整洁-

public class SomeState : State
{
    public override string name => "State_1";
}

两者都将始终返回“ State_1”并且是不可变的。


1
可以编写public override string name { get; } = "State_1";此代码,这样就不必每次都重新评估该值。
戴夫·库西诺

2

您的要求是矛盾的:

我正在尝试为每个名为StateName的州创建String属性。

但是我不需要每个州实施所有这些措施。

没有语言功能可让您仅在几个子类中强制成员的存在。毕竟,使用超类的目的是要依靠这样一个事实,即所有子类都将具有超类的所有成员(可能还有更多)。如果您要创建充当a State但没有名称的类,则根据定义,它们不应(/可以)是的子类State

您要么更改您的要求,要么使用简单继承之外的其他方法。

使用代码的可能解决方案可能是使该方法成为State非抽象方法并返回空字符串。


我认为您是在没有上下文的情况下采纳了第二个声明,但我会澄清。我不需要Get / Set方法,只需要StateName = "MyState1"在每个州使用。如果状态类中没有该语句,则理想情况下Visual Studio将生成错误。
GisMofx

3
@GisMofx如果要在每个子类中强制使用状态名称,请使其抽象,但不需要状态。然后,每个子类都必须提供return "MyState1"其实现,并且可以在需要时为该值添加可变存储。但是您需要澄清问题的要求-每种状态都需要一个可以读取的StateName,并且任何类型的状态都要求在创建后对其进行更改吗?
Pete Kirkham

@PeteKirkham每个州都需要一个名称,创建后不应对其进行更改。各州的名称是静态/不可变的。
GisMofx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.