예제 #1
0
        async Task InternalFireOneAsync(TTrigger trigger, params object[] args)
        {
            TriggerWithParameters configuration;

            if (_triggerConfiguration.TryGetValue(trigger, out configuration))
            {
                configuration.ValidateParameters(args);
            }

            var source = State;
            var representativeState = GetRepresentation(source);

            TriggerBehaviourResult result;

            if (!representativeState.TryFindHandler(trigger, args, out result))
            {
                await _unhandledTriggerAction.ExecuteAsync(representativeState.UnderlyingState, trigger, result?.UnmetGuardConditions).ConfigureAwait(false);

                return;
            }

            TState destination;

            if (result.Handler.ResultsInTransitionFrom(source, args, out destination))
            {
                var transition = new Transition(source, destination, trigger);

                transition = await representativeState.ExitAsync(transition).ConfigureAwait(false);

                State = transition.Destination;
                var newRepresentation = GetRepresentation(transition.Destination);
                await _onTransitionedEvent.InvokeAsync(transition).ConfigureAwait(false);

                await newRepresentation.EnterAsync(transition, args).ConfigureAwait(false);
            }
            else
            {
                var transition = new Transition(source, destination, trigger);

                await CurrentRepresentation.InternalActionAsync(transition, args).ConfigureAwait(false);
            }
        }
예제 #2
0
 /// <summary>
 /// The currently-permissible trigger values.
 /// </summary>
 public IEnumerable <TTrigger> GetPermittedTriggers(params object[] args)
 {
     return(CurrentRepresentation.GetPermittedTriggers(args));
 }
예제 #3
0
        async Task InternalFireOneAsync(TTrigger trigger, params object[] args)
        {
            // If this is a trigger with parameters, we must validate the parameter(s)
            if (_triggerConfiguration.TryGetValue(trigger, out var configuration))
            {
                configuration.ValidateParameters(args);
            }

            var source = State;
            var representativeState = GetRepresentation(source);

            // Try to find a trigger handler, either in the current state or a super state.
            if (!representativeState.TryFindHandler(trigger, args, out var result))
            {
                await _unhandledTriggerAction.ExecuteAsync(representativeState.UnderlyingState, trigger, result?.UnmetGuardConditions).ConfigureAwait(false);

                return;
            }
            // Check if this trigger should be ignored
            if (result.Handler is IgnoredTriggerBehaviour)
            {
                return;
            }

            // Handle special case, re-entry in superstate
            if (result.Handler is ReentryTriggerBehaviour handler)
            {
                // Handle transition, and set new state
                var transition = new Transition(source, handler.Destination, trigger);
                transition = await representativeState.ExitAsync(transition);

                State = transition.Destination;
                var newRepresentation = GetRepresentation(transition.Destination);

                if (!source.Equals(transition.Destination))
                {
                    // Then Exit the final superstate
                    transition = new Transition(handler.Destination, handler.Destination, trigger);
                    await newRepresentation.ExitAsync(transition);
                }

                await _onTransitionedEvent.InvokeAsync(new Transition(source, handler.Destination, trigger));

                await newRepresentation.EnterAsync(transition, args);
            }
            // Check if it is an internal transition, or a transition from one state to another.
            else if (result.Handler.ResultsInTransitionFrom(source, args, out var destination))
            {
                var transition = new Transition(source, destination, trigger);

                transition = await representativeState.ExitAsync(transition).ConfigureAwait(false);

                State = transition.Destination;
                var newRepresentation = GetRepresentation(transition.Destination);

                // Check if there is an intital transition configured
                if (newRepresentation.HasInitialTransition)
                {
                    // Verify that the target state is a substate
                    if (!newRepresentation.GetSubstates().Any(s => s.UnderlyingState.Equals(newRepresentation.InitialTransitionTarget)))
                    {
                        throw new InvalidOperationException($"The target ({newRepresentation.InitialTransitionTarget}) for the initial transition is not a substate.");
                    }

                    // Check if state has substate(s), and if an initial transition(s) has been set up.
                    while (newRepresentation.GetSubstates().Any() && newRepresentation.HasInitialTransition)
                    {
                        var initialTransition = new Transition(source, newRepresentation.InitialTransitionTarget, trigger);
                        newRepresentation = GetRepresentation(newRepresentation.InitialTransitionTarget);
                        await newRepresentation.EnterAsync(initialTransition, args);

                        State = newRepresentation.UnderlyingState;
                    }
                    //Alert all listeners of state transition
                    await _onTransitionedEvent.InvokeAsync(new Transition(source, destination, trigger));
                }
                else
                {
                    //Alert all listeners of state transition
                    await _onTransitionedEvent.InvokeAsync(new Transition(source, destination, trigger));

                    await newRepresentation.EnterAsync(transition, args);
                }
            }
            else
            {
                var transition = new Transition(source, destination, trigger);

                await CurrentRepresentation.InternalActionAsync(transition, args).ConfigureAwait(false);
            }
        }