c# - 需要帮助使用继承来接受有限状态机中的派生类型参数

标签 c# inheritance unity3d polymorphism abstract

我刚刚开始尝试使用一些抽象类和继承来编写一个有限状态机,其中状态和状态机可以被继承,以便该框架可以用于不同类型的 AI。

问题是继承的类一直期待其参数的基类型,不接受派生类型,我不确定我是在以错误的方式处理它还是只是以错误的方式编码。 (据我了解,我正在尝试实现 Liskov Substitution Principle )

基本代码:

public abstract class State {
    public abstract void BeginState(StateMachine stateMachine);
    public abstract void UpdateState(StateMachine stateMachine);
    public abstract void EndState(StateMachine stateMachine);
}

public class StateMachine : MonoBehaviour {
    //Stuff here to execute the current state, store previous state, revert states, etc. 
    //Example:
    private State currentState;
    private State previousState;
    public virtual void SwitchState(State newState) {
        //Switch state, store previous state if not null
        if (currentState != null) {
            previousState = currentState;
            currentState.EndState(this);
        }        
        currentState = newState;
        currentState.BeginState(this);
    }
}

这个想法是,这些可以被继承和扩展,以用于人类 ai、僵尸 ai、机器人 ai 等:

public class Idle : State
{
    //Begin, Update, and End states here. Example:
    public override void BeginState(ZombieStateMachine ZSM)
    {
        Debug.Log("Begin idling");
    }
}

public class ZombieStateMachine : StateMachine {
    public Idle idleState = new Idle();
    void Start {
        SwitchState(idleState);
    }
}

问题出在继承自抽象 State 类的 Idle 状态。我正在尝试通过继承了 StateMachine 的 ZombieStateMachine,但是 Idle 类抛出错误,而是期望 StateMachine。 (编辑:该错误是编译时错误,而不是我错误暗示的运行时错误)

如有任何帮助,我们将不胜感激。

最佳答案

这是否如您的描述所暗示的那样是运行时错误?或者这是一个编译时错误?我怀疑是后者,因为:

public override void BeginState(ZombieStateMachine ZSM)

实际上并没有覆盖这个:

public abstract void BeginState(StateMachine stateMachine)

覆盖需要是相同的类型:

public override void BeginState(StateMachine ZSM)

在这种情况下,里氏替换原则的想法是 BeginState 方法中的任何内容都不应该关心它所提供的StateMachine种类,它应该只与基本的 StateMachine 操作交互。

您的两个基类相互传递似乎有点奇怪。 State 上的方法需要一个 StateMachine,而 StateMachine 上的方法需要一个 State。目前还不清楚为什么会这样。

虽然如果确实需要这样,那么我想知道您是否可以从泛型基类型中受益。像这样:

public abstract class State<T> where T : StateMachine
{
    public abstract void BeginState(T stateMachine);
    public abstract void UpdateState(T stateMachine);
    public abstract void EndState(T stateMachine);
}

然后用指定的类型继承:

public class Idle : State<ZombieStateMachine>
{
    //Begin, Update, and End states here. Example:
    public override void BeginState(ZombieStateMachine ZSM)
    {
        Debug.Log("Begin idling");
    }
}

这是徒手编写的代码,所以我不是100% 确定它是否有效,但对我来说似乎是合理的。 (如果不正确,我会继续并删除此答案。)

这种种类限制了您尝试的纯多态性,因为子类型不再接受任何实现基类型的类型。但看起来这就是您对用法的期望,一个类的给定子类型本质上将与另一个类的相应子类型“配对”。通过使用泛型,它们可以显式配对。

关于c# - 需要帮助使用继承来接受有限状态机中的派生类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32145195/

相关文章:

C# 3.0 目标 2.0

c# - 有什么可以用 C# 事件做而不能用 VB 事件做的事情吗?

c# - 多 map /减少在 RavenDb 中工作吗?

java - Hibernate 从同一个请求返回同一个实体,但在一种情况下它被代理,而在第二种情况下它不是。为什么?

javascript通过继承实现私有(private)变量

c# - 如果值匹配多个键,则从字典中删除所有键

python - 继承:更改子方法的签名

c# - 激活和停用调用功能

c# - 为什么新的实例化预制件与原始选定游戏对象的位置不同?

c# - 如果像素是透明的,不要将像素设置到 Texture2D 中