Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 需要使用继承在有限状态机中接受派生类型参数的帮助吗_C#_Inheritance_Unity3d_Polymorphism_Abstract - Fatal编程技术网

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

C# 需要使用继承在有限状态机中接受派生类型参数的帮助吗,c#,inheritance,unity3d,polymorphism,abstract,C#,Inheritance,Unity3d,Polymorphism,Abstract,我刚刚开始尝试使用一些抽象类和继承来编写一个有限状态机,其中状态和状态机可以被继承,这样框架就可以用于不同类型的AI 问题是继承的类一直期望其参数的基类型,而不接受派生类型,我不确定我是以错误的方式进行操作,还是仅仅以错误的方式进行编码。(据我所知,我正在努力实施) 基本代码: public abstract class State { public abstract void BeginState(StateMachine stateMachine); public abstr

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

问题是继承的类一直期望其参数的基类型,而不接受派生类型,我不确定我是以错误的方式进行操作,还是仅仅以错误的方式进行编码。(据我所知,我正在努力实施)

基本代码:

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);
    }
}
从抽象状态类继承的空闲状态会出现问题。我试图通过ZombieStateMachine,它继承了StateMachine,但是Idle类抛出一个错误,并期望使用StateMachine。(编辑:该错误是编译时错误,而不是我错误地暗示的运行时错误)

非常感谢您的帮助。

这是您描述的运行时错误吗?或者这是一个编译时错误?我怀疑是后者,因为:

public override void BeginState(ZombieStateMachine ZSM)
实际上并没有覆盖这一点:

public abstract void BeginState(StateMachine stateMachine)
覆盖需要是相同的类型:

public override void BeginState(StateMachine ZSM)
在这种情况下,Liskov替换原则的思想是,
begintate
方法中的任何内容都不应该关心给定的
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);
}
公共抽象类状态,其中T:StateMachine
{
公开摘要无效开始(T状态机);
公共抽象资产(T状态机);
公共抽象void EndState(T状态机);
}
然后使用指定的类型继承:

public class Idle : State<ZombieStateMachine>
{
    //Begin, Update, and End states here. Example:
    public override void BeginState(ZombieStateMachine ZSM)
    {
        Debug.Log("Begin idling");
    }
}
公共类空闲:状态
{
//此处的开始、更新和结束状态。示例:
公共覆盖void BeginState(ZombieStateMachine ZSM)
{
Log(“开始空转”);
}
}
这是写意代码,所以我不是100%确定它是否有效,但对我来说似乎是合理的。(如果不正确,我将继续删除此答案。)


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

请详细说明您希望在方法声明中使用
ZombieStateMachine
而不是
StateMachine
。事实上,正如编译器所说,您必须使用被重写方法的确切方法签名;这里只允许使用
StateMachine
。但是使用抽象/多态性等的目的是让调用方不必知道所使用对象的实际实现类型。如果希望对传递给对象的类型有编译时限制,那么使用多态方法可能不适合您。提供更多关于您真正目标的详细信息在这里会有所帮助。我想使用
ZombieStateMachine
而不是
StateMachine
的原因是所有状态机都将使用该框架,但
ZombieStateMachine
脚本内部也将是唯一的僵尸状态类,如
HuntPlayer
Idle
grampobject
但也在
ZombieStateMachine
中是移动僵尸所需的变量,因此
NavMeshAgent
ZombieThirdPersonAnimator
等等。我认为这种多态方法将减少我必须重复的代码量,因为否则我必须为每种不同的AI类型重复完全相同的
StateMachine
代码。你能发布例外情况吗?来自Unity:“资产/_脚本/_Zombies/ZombieStateMachine.cs(55,26):错误CS0115:`Idle.begintate”(ZombieStateMachine)“”标记为重写,但找不到可重写的合适方法”一些建议:你的状态机应该只是这样。它应该维护state.Period。让其他类在状态机报告状态并做出相应响应时使用状态。这样,你的僵尸特定代码就根本不是一个状态机,而只是组成一个状态机。状态机应该严格地接受输入,ap应用到当前状态,并确定新状态。使用correct,您的类型冲突问题将消失。很抱歉,您是正确的,这是一个编译时错误。(我将查看您的代码是否适用于我。)我尝试了你的代码。我遇到了一个问题,在使用状态声明的StateMachine内部,它现在也需要为这些声明指定一个类型。例如,
public void SwitchState(State newState){}
,当从
ZSM
作为
SwitchState(idlstate)
调用时,它不再工作(因为我猜idlstate是ZSM类型的?)@Visulth:啊,你说得对。这会产生一种循环依赖。我想这可以追溯到问题……为什么两个基类型都需要相互引用?我希望一个引用另一个,但不是两个都互相引用。为什么需要为
St上的方法提供
StateMachine
ate
?我希望一个“状态”本身是一个离散的东西,“状态机”会对一组状态执行操作。好吧,也许我说的不对