1

好吧,这需要一些解释,所以这里是:

我正在为视频游戏制作有限状态机,其中状态是从 State 基类派生的对象。由于状态是对象,因此每个状态都必须在成为当前状态之前进行实例化。每个状态都可以有可以输入的子状态(仍然只是从状态派生),这就是我遇到问题的地方。我需要能够存储每个子状态的类型的集合。举一个具体的例子,这是我对这项工作的设想(我意识到这段代码中有一些不好的做法,但这只是目标的一个例子,而不是我打算直接使用的代码):

public abstract class State
{
    private Type[] subStates = new Type[0];
    private State currentState;

    public GoToSubState<T> () where T : State, new()
    {
        if ( subStates.Contains(T) )
        {
            currentState = new T();
        }
    }

    //...
}

public class StateOne : State
{
    public StateOne ()
    {
        subStates = new[] { typeof(SubStateA), typeof(SubStateB) };
    }

    //...
}

public class SubStateA
{
    //...
}

public class SubStateB
{
    //...
}

现在,虽然这或多或少有效,但它不是类型安全的。由于subStates是一个 Type 数组,因此不能保证它们是从 State 派生的。一种解决方法是使用可以在编译时强制执行基本类型的 register 方法:

public abstract class State
{
    private List<Type> subStates = new List<Type>;

    public RegisterSubState<T> () where T : State
    {
        subStates.Add(T);
    }

    //...
}

public class StateOne : State
{
    public StateOne ()
    {
        RegisterSubState<SubStateA>();
        RegisterSubState<SubStateB>();
    }

    //...
}

但这有点不那么有吸引力。还有其他方法可以完成我的任务吗?最终,我真正需要的只是能够设置类型的集合,但要保证它们的类型在编译时从 State 派生。

4

2 回答 2

2

你所拥有的确实是最优雅的方式。您正在让编译器强制执行您想要的限制,同时只记录您想要的类型。

另一种方法是在每个状态中存储状态实例。然后您可以将您的集合公开为包含States 而不是Types。但也许这不适合您的应用程序。

于 2013-07-17T18:24:13.850 回答
0

我认为您可以创建一个继承List<Type>并覆盖 Add 函数的类,以便强制执行类型安全(没有后门,用户可以直接调用 Add 而不是使用您的 register 方法)。所以基本上;

public class StateList : List<Type>
{
     public override void Add(Type t)
     {
         if (typeof(t).IsSubclassOf(typeof(State))
         {
         }
         else
             throw new InvalidArgumentException();
     }
}

然后在状态类中,您将只拥有一个StateList属性而不是一个List<Type>属性。我的示例代码可能需要稍作调整,但我认为这个概念是成立的。请注意,您还必须覆盖AddRange另一个将新对象放入集合中的方法。

于 2013-07-17T18:28:59.650 回答