Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何封装.NET无状态状态机_C#_Stateless State Machine - Fatal编程技术网

C# 如何封装.NET无状态状态机

C# 如何封装.NET无状态状态机,c#,stateless-state-machine,C#,Stateless State Machine,我有一个项目,主要是线性工作流程。我正在尝试使用.NET无状态机作为工作流引擎/状态机。示例的数量是有限的,但我将以下代码放在一起: private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine; private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, Da

我有一个项目,主要是线性工作流程。我正在尝试使用.NET无状态机作为工作流引擎/状态机。示例的数量是有限的,但我将以下代码放在一起:

private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine;
private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, DateTime> registrationTrigger;
private Patient patient;

public Patient RegisterPatient(DateTime dateOfBirth)
{
    configureStateMachine(WorkflowState.Unregistered);
    stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
    logger.Info("State changed to: " + stateMachine.State);
    return patient;
}

private void configureStateMachine(WorkflowState state)
{
    stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(state);

    registrationTrigger = stateMachine.SetTriggerParameters<DateTime>(WorkflowTrigger.Register);

    stateMachine.Configure(WorkflowState.Unregistered)
        .Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);

    stateMachine.Configure(WorkflowState.Registered)
        .Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
        .OnEntryFrom(registrationTrigger, (dateOfBirth) => registerPatient(dateOfBirth));
}

private void registerPatient(DateTime dateOfBirth)
{
    //Registration code
}
私有状态机状态机;
private StateMachine.TriggerWithParameters registrationTrigger;
私家病人;
公共患者登记患者(出生日期时间)
{
configureStateMachine(WorkflowState.未注册);
stateMachine.Fire(注册触发器,出生日期);
logger.Info(“状态更改为:“+stateMachine.State”);
返回病人;
}
私有void配置状态机(WorkflowState状态)
{
stateMachine=新的stateMachine(状态);
registrationTrigger=stateMachine.SetTriggerParameters(WorkflowTrigger.Register);
stateMachine.Configure(WorkflowState.Unregisted)
.许可证(WorkflowTrigger.Register,WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling,WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger,(出生日期)=>registerPatient(出生日期));
}
私人无效登记患者(出生日期时间日期)
{
//注册码
}
如您所见,我正在使用无状态Fire()重载,它允许我传入触发器。这样我就可以拥有状态机流程业务逻辑,在本例中,是注册新患者的代码

这一切都是可行的,但现在我想把所有的状态机代码移到另一个类中来封装它,我在这样做时遇到了麻烦。我在这方面遇到的挑战是:

  • 实例化
    StateMachine
    对象需要指定状态,并且
    state
    是只读属性,只能在实例化时设置
  • my
    registrationTrigger
    必须在状态机配置期间实例化,并且必须由调用类提供
如何克服这些问题并封装状态机代码?

有一个由Scott Hanselman编写的示例和库介绍。在他们的GitHub上也没有几个例子,包括Scott的文章中提到的封装状态机的例子

下面是如何从行为中提取状态的示例:

public class PatientRegistrationState
{
    private StateMachine<WorkflowState, WorkflowTrigger> stateMachine;
    private StateMachine<WorkflowState, WorkflowStateTrigger>.TriggerWithParameters<DateTime> registrationTrigger;

    public PatientRegistrationState(State initialState = default(State)) {
        stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(initialState);

        stateMachine.Configure(WorkflowState.Unregistered)
            .Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);

        stateMachine.Configure(WorkflowState.Registered)
            .Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
            .OnEntryFrom(registrationTrigger, (date) => OnPatientRegistered(date));
    }

    public WorkflowState State => stateMachine.State;
    public Action<DateTime> OnPatientRegistered {get; set;} = (date) => { };

    // For state changes that do not require parameters.
    public void ChangeTo(WorkflowTrigger trigger)
    {
        stateMachine.Fire<DateTime>(trigger);
    }

    // For state changes that require parameters.
    public void ChangeToRegistered(DateTime dateOfBirth)
    {
        stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);        
    }

    // Change to other states that require parameters...
}

public class PatientRegistration
{
    private PatientRegistrationState registrationState;
    private Patient patient;

    public PatientRegistration()
    {
        registrationState = PatientRegistrationState(WorkflowState.Unregistered)
        {
            OnPatientRegistered = RegisterPatient;
        }
    }

    public Patient RegisterPatient(DateTime dateOfBirth)
    {
        registrationState.ChangeToRegistered(dateOfBirth);
        logger.Info("State changed to: " + registrationState.State);
        return patient;
    }

    private void RegisterPatient(DateTime dateOfBirth)
    {
        // Registration code
    }
}
公共类PatientRegistrationState
{
私有状态机;
private StateMachine.TriggerWithParameters registrationTrigger;
public PatientRegistrationState(状态initialState=默认(状态)){
stateMachine=新的stateMachine(initialState);
stateMachine.Configure(WorkflowState.Unregisted)
.许可证(WorkflowTrigger.Register,WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling,WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger,(date)=>OnPatientRegistered(date));
}
公共WorkflowState=>stateMachine.State;
公共操作OnPatientRegistered{get;set;}=(日期)=>{};
//用于不需要参数的状态更改。
公共作废更改为(WorkflowTrigger触发器)
{
状态机。点火(触发器);
}
//用于需要参数的状态更改。
公共无效更改已注册(日期时间出生日期)
{
stateMachine.Fire(注册触发器,出生日期);
}
//更改为需要参数的其他状态。。。
}
公共类病人登记
{
私人病人注册州注册州;
私家病人;
公众病人登记()
{
registrationState=PatientRegistrationState(WorkflowState.Unregisted)
{
OnPatientRegistered=登记患者;
}
}
公共患者登记患者(出生日期时间)
{
注册状态变更注册(出生日期);
logger.Info(“状态更改为:“+registrationState.State”);
返回病人;
}
私人无效登记患者(出生日期时间日期)
{
//注册码
}
}

这就是我在项目中实现它的方式

分离工作流逻辑以分离类。我有两个基于请求对象中存在的一个标志的工作流;以下是其中一个工作流类:

public class NationalWorkflow : BaseWorkflow
{
    public NationalWorkflow(SwiftRequest request) : this(request, Objects.RBDb)
    { }

    public NationalWorkflow(SwiftRequest request, RBDbContext dbContext)
    {
        this.request = request;
        this.dbContext = dbContext;
        this.ConfigureWorkflow();
    }

    protected override void ConfigureWorkflow()
    {
        workflow = new StateMachine<SwiftRequestStatus, SwiftRequestTriggers>(
           () => request.SwiftRequestStatus, state => request.SwiftRequestStatus = state);

        workflow.OnTransitioned(Transitioned);

        workflow.Configure(SwiftRequestStatus.New)
            .OnEntry(NotifyRequestCreation)
            .Permit(SwiftRequestTriggers.ProcessRequest, SwiftRequestStatus.InProgress);

        workflow.Configure(SwiftRequestStatus.InProgress)
            .OnEntry(ValidateRequestEligibility)
            .Permit(SwiftRequestTriggers.AutoApprove, SwiftRequestStatus.Approved)
            .Permit(SwiftRequestTriggers.AdvancedServicesReview, SwiftRequestStatus.PendingAdvancedServices);

.....................
}
如上所述,我根据请求对象中的条件使用了不同的工作流规则,因此使用了工厂模式
WorkflowFactory.Get(request)
;您可以根据需要创建工作流实例/注入它

在workflow类(在我的例子中是BaseWorkflow类)中,我公开了以下操作:

    public void UpdateRequest()
    {
        using (var trans = this.dbContext.Database.BeginTransaction())
        {
            this.actionComments = "Updating the request";
            this.TryFire(SwiftRequestTriggers.Update);

            SaveChanges();
            trans.Commit();
        }
    }

  protected void TryFire(SwiftRequestTriggers trigger)
    {
        if (!workflow.CanFire(trigger))
        {
            throw new Exception("Cannot fire " + trigger.ToString() + " from state- " + workflow.State);
        }
        workflow.Fire(trigger);
    }

Hanselman的文章是我最初实现的基础,我在github上看到了这个示例。两者都涉及与使用者在同一个类中的状态机代码。@im1dermike我想我理解您试图实现的目标。请看一下我对我的答案所做的编辑。现在正在尝试实现这一点。我想您在这一行有at类型:
publicworkflowstate状态{get;}=>stateMachine.State谢谢你的回答。我能够在我的项目中实现这一点,并且成功了。最终,我决定使用无状态与所获得的相比,开销实在太大了。@im1dermike您能解释一下您是如何解决问题的,还是添加一个更好的答案?我现在的处境和你一样
    public void UpdateRequest()
    {
        using (var trans = this.dbContext.Database.BeginTransaction())
        {
            this.actionComments = "Updating the request";
            this.TryFire(SwiftRequestTriggers.Update);

            SaveChanges();
            trans.Commit();
        }
    }

  protected void TryFire(SwiftRequestTriggers trigger)
    {
        if (!workflow.CanFire(trigger))
        {
            throw new Exception("Cannot fire " + trigger.ToString() + " from state- " + workflow.State);
        }
        workflow.Fire(trigger);
    }