public MobTransitionResult Go(IEvent @event, Tuple <TEntity1, TEntity2> mob) { if (Stators.Count != 2) { throw StatorConfigurationException.MobEntitiesAndStateMachinesCountNotEquals(2, Stators.Count); } var rollbackActions = new List <Action>(); var transitionActions = new List <Func <Tuple <Type, bool, FailureTypes> > >(); PrepareDelegates(mob.Item1, @event, rollbackActions, transitionActions); PrepareDelegates(mob.Item2, @event, rollbackActions, transitionActions); try { return(ProcessResult(transitionActions.Select(x => x?.Invoke()).ToArray())); } catch { if (_withRollbackOnFailure) { rollbackActions.ForEach(x => x?.Invoke()); } throw; } }
private void BuildMap(object[] mobEntity) { var count = mobEntity.Length; _typePreparersMap = new Dictionary <Type, Action <object, IEvent, List <Action>, List <Func <Tuple <Type, bool, FailureTypes> > > > >(); var touchedEntities = new Type[count]; for (var i = 0; i < count; i++) { var entity = mobEntity[i]; var entityType = entity.GetType(); if (Array.IndexOf(touchedEntities, entityType) >= 0) { throw StatorConfigurationException.MobStatorCantPropessDuplicatedEntities(entityType); } touchedEntities[i] = entityType; var constThis = Expression.Constant(this); var inEntityParam = Expression.Parameter(typeof(object), "entity"); var entityParam = Expression.Convert(inEntityParam, entityType); var eventParam = Expression.Parameter(typeof(IEvent), "@event"); var rollbackActionsParam = Expression.Parameter(typeof(List <Action>), "rollbackActions"); var transitionInvokersParam = Expression.Parameter(typeof(List <Func <Tuple <Type, bool, FailureTypes> > >), "transitionInvokers"); var callExp = Expression.Call(constThis, nameof(PrepareDelegates), new Type[] { entityType }, new Expression[] { entityParam, eventParam, rollbackActionsParam, transitionInvokersParam }); var lambda = Expression.Lambda(callExp, new[] { inEntityParam, eventParam, rollbackActionsParam, transitionInvokersParam }); var compiled = (Action <object, IEvent, List <Action>, List <Func <Tuple <Type, bool, FailureTypes> > > >)lambda.Compile(); _typePreparersMap.Add(entityType, compiled); } }
public MobTransitionResult Go(IEvent @event, params object[] mob) { if (_typePreparersMap == null) { BuildMap(mob); } var entitiesCount = mob.Length; if (Stators.Count != entitiesCount) { throw StatorConfigurationException.MobEntitiesAndStateMachinesCountNotEquals(entitiesCount, Stators.Count); } var rollbackActions = new List <Action>(); var transitionActions = new List <Func <Tuple <Type, bool, FailureTypes> > >(); foreach (var item in mob) { _typePreparersMap[item.GetType()](item, @event, rollbackActions, transitionActions); } try { return(ProcessResult(transitionActions.Select(x => x?.Invoke()).ToArray())); } catch { if (_withRollbackOnFailure) { rollbackActions.ForEach(x => x?.Invoke()); } throw; } }
internal void AddStatorNode <TEntity, TEntityState>(IStator <TEntity, TEntityState> stator) where TEntity : class { var nodeType = typeof(TEntity); if (Stators.Keys.Contains(nodeType)) { throw StatorConfigurationException.MobStatorCantSetForDuplicatedEntities(nodeType); } var accessor = new EntityGetSetAccessor { TransitionInvoker = (entity, @event) => stator.Go((TEntity)entity, (IEvent)@event), GetInvoker = (entity) => stator.GetGetter()((TEntity)entity), SetInvoker = (entity, state) => stator.GetSetter()((TEntity)entity, (TEntityState)state) }; Stators[nodeType] = accessor; }
protected void PrepareDelegates <T>(T entity, IEvent @event, List <Action> rollbackActions, List <Func <Tuple <Type, bool, FailureTypes> > > transitionActions) where T : class { var type = typeof(T); if (!Stators.TryGetValue(type, out var entityAccessor) || entityAccessor == null) { throw StatorConfigurationException.MobEntityStateMachineNotRegistered(type); } var transitionInvoker = entityAccessor.TransitionInvoker; var setInvoker = entityAccessor.SetInvoker; var getInvoker = entityAccessor.GetInvoker; var oldValue = getInvoker(entity); Action rollbackAction = () => setInvoker(entity, oldValue); rollbackActions.Add(rollbackAction); transitionActions.Add(() => { var result = (TransitionResult <T>)transitionInvoker(entity, @event); return(Tuple.Create(type, result.Success, result.FailureType)); }); }