从类型集合中实例化类

时间:2013-07-17 18:19:24

标签: c# types state

好的,这需要一些解释,所以这里有:

我正在为视频游戏制作一个有限状态机,其中状态是从State基类派生的对象。由于状态是对象,因此每个状态必须在它变为当前状态之前被实例化。每个州都可以拥有可以输入的子状态(它们仍然只来自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。一种解决方法是使用可在编译时强制执行基类型的寄存器方法:

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派生。

2 个答案:

答案 0 :(得分:2)

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

另一种方法是在每个州内存储州的实例。然后,您可以将您的收藏展示为包含State而不是Type s。但也许这不适合您的申请。

答案 1 :(得分: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以及将新对象放入集合的其他方法。