我刚接触状态机,并尝试使用状态机完成提交,审核和批准方案的过程。它在fsm.ProcessEvent(FiniteStateMachine.Events.Reviewed);
上引发错误
即对象引用null异常。我想不出来?我是否正确实施了方案?
class Program
{
static void Main(string[] args)
{
var fsm = new FiniteStateMachine();
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.Submitted);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.Reviewed);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.Approved);
Console.WriteLine(fsm.State);
Console.ReadKey();
}
class FiniteStateMachine
{
public enum States { Submitted, Reviewed, Approved};
public States State { get; set; }
public enum Events { Submitted, Reviewed, Approved};
private Action[,] fsm;
public FiniteStateMachine()
{
this.fsm = new Action[3, 3] {
//Submitted, Reviewed, TurnOff,
{this.SubmittedForReview, null, null }, //Submitted
{null, this.Reviewing, null }, //Reviewed
{null, null, this.Approving} }; //Approved
}
public void ProcessEvent(Events theEvent)
{
this.fsm[(int)this.State, (int)theEvent].Invoke();
}
private void SubmittedForReview() { this.State = States.Submitted; }
private void Reviewing() { this.State = States.Reviewed; }
private void Approving() { this.State = States.Approved; }
}
}
}
我认为问题在于你的FSM。您正在创建一个多维操作数组。而是尝试查找,就像字典一样。这里有一个字典,其中键是状态,值是您要采取的操作。这对我有用。这是我改变的。
private Dictionary<int, Action> fsm;
public FiniteStateMachine()
{
this.fsm = new Dictionary<int, Action>() {
{ (int)States.Submitted, SubmittedForReview },
{(int)States.Reviewed, Reviewing },
{(int)States.Approved, Approving}
};
}
public void ProcessEvent(Events theEvent)
{
var action = fsm[(int)theEvent];
action.Invoke();
}
编辑1
处理已审核时获取空引用的原因是因为State设置为Submitted。 C#中的枚举从0开始,所以当你打电话时
fsm.ProcessEvent(FiniteStateMachine.Events.Reviewed);
你想要查找的是什么?
public void ProcessEvent(Events theEvent)
{
//this.fsm[(int)this.State, (int)theEvent].Invoke();
this.fsm[0, 1].Invoke();
}
因为this.State仍然是Submitted。因此,您尝试在索引0的索引1处调用该操作,该操作为null。希望有所帮助。
在你的情况下,有一个对象引用null异常是正常的,因为你没有一个已审查状态的事件已提交你需要安排你的数组。
你可以使用下面的代码来避免对象引用null异常(c#6的特性)
public void ProcessEvent(Events theEvent)
{
this.fsm[(int)this.State, (int)theEvent]?.Invoke();
}