问题描述
我正在尝试制作一个状态机,如果我的操作以 OK 状态结束,它应该发送电子邮件,或者它应该重复该操作至少 n 次,直到它以 OK 状态结束。如果超过 n 次阈值,状态机应该只是回滚并停止。
我尝试了状态和提供的一些方法,但我无法在 if 中使用 TransitionTo(State) 方法来充当“goto”并跳转到状态而忽略每一行代码低于这个点。
所以,把它放在 C# 伪代码中,它看起来像这样(这只是一种表示,以防状态机代码难以理解,我没有在我的应用程序中使用这段代码):
numberOfRetries = 5;
CheckActionStatus:
if (GetActionStatus() == Status.OK)
{
return SendEmailToUser();
}
else
{
numberOfRetries--;
}
if (numberOfRetries > 0)
{
goto CheckActionStatus;
}
else
{
return RollbackAction();
}
以及我使用的状态机代码(请记住,numberOfRetries 的递减是在 GetActionStatus() 中完成的)
WhenEnter(Check,binder => binder
.Then(x => x.Instance.ActionStatus = GetActionStatus())
.If(x => x.Instance.ActionStatus == Status.OK,x => x.TransitionTo(SendEmailToUser))
.IfElse(x => x.Instance.NumberOfRetries > 0,x => x.TransitionTo(Check),x => x.TransitionTo(Rollback)));
WhenEnter(SendEmailToUser,binder => binder
.Then(x => Console.WriteLine("Email sent to user,everything ok!"))
.Finalize());
WhenEnter(Rollback,binder => binder
.Then(x => Console.WriteLine("Rollbacked!"))
.Finalize());
SetCompletedWhenFinalized();
但是当我运行状态机时,我得到的输出是:
Email sent to user,everything ok!
Rollbacked!
当预期的输出应该只是
Email sent to user,everything ok!
或者只是
Rollbacked!
因为我希望如果第一个 if 有一个真条件,它应该转移到下一个状态(在我的例子中是 SendEmailToUser)并从那里继续执行。只有当条件评估为假时,它才应该继续第二个if(检查重试的那个)。
我错过了什么吗?
解决方法
转换到另一个状态不会转移活动执行,而是会继续下一个 IfElse
活动。所以你需要两者都是 IfElse 活动。
在 Chris 的回答之后,我以两种不同的方式改变了我实现状态机的方式: 方法一:嵌套if-else
WhenEnter(Check,binder => binder
.Then(x => x.Instance.ActionStatus = GetActionStatus())
.IfElse(x => x.Instance.ActionStatus == Status.OK,x => x.TransitionTo(SendEmailToUser),xx => xx.IfElse(xy => xy.Instance.NumberOfRetries > 0,x => x.TransitionTo(Check),x => x.TransitionTo(Rollback))));
WhenEnter(SendEmailToUser,binder => binder
.Then(x => Console.WriteLine("Email sent to user,everything ok!"))
.Finalize());
WhenEnter(Rollback,binder => binder
.Then(x => Console.WriteLine("Rollbacked!"))
.Finalize());
SetCompletedWhenFinalized();
这样,状态以 if-else 结束,不再执行任何其他操作,确保完成到所需状态的转换。
方法二:中间状态
WhenEnter(Check,x => x.TransitionTo(RetryCheck)));
WhenEnter(RetryCheck,binder => binder
.IfElse(x => x.Instance.NumberOfRetries > 0,x => x.TransitionTo(Rollback)));
WhenEnter(SendEmailToUser,binder => binder
.Then(x => Console.WriteLine("Rollbacked!"))
.Finalize());
SetCompletedWhenFinalized();
这种方法也有效,我发现它更容易理解,因为您基本上只是向状态机添加另一个条件。