好的,这需要一些解释,所以这里有:
我正在为视频游戏制作一个有限状态机,其中状态是从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派生。
答案 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
以及将新对象放入集合的其他方法。