/// <summary> /// Performs a dynamic transition; i.e., the transition path is determined on the fly and not recorded. /// </summary> /// <param name="targetState">The <see cref="QState"/> to transition to.</param> protected void TransitionTo(QState targetState) { Debug.Assert(targetState != s_TopState); // can't target 'top' state OnEvent(targetState.GetMethodInfo()); ExitUpToSourceState(); // This is a dynamic transition. We pass in null instead of a recorder TransitionFromSourceToTarget(targetState.GetMethodInfo(), null); OnEvent(null); }
private void TransitionToSynchronized(QState targetState, ref TransitionChain transitionChain) { //The entire method had been embedded within [MethodImpl(MethodImplOptions.Synchronized)], //which is not available in .NET Core, and so a lock is used instead... lock (this) { if (transitionChain != null) { // We encountered a race condition. The first (non-synchronized) check indicated that the transition chain // is null. However, a second threat beat us in getting into this synchronized method and populated // the transition chain in the meantime. We can execute the regular method again now. TransitionTo(targetState, ref transitionChain); } else { // The transition chain is not initialized yet, we need to dynamically retrieve // the required transition steps and record them so that we can subsequently simply // play them back. TransitionChainRecorder recorder = new TransitionChainRecorder(); TransitionFromSourceToTarget(targetState.GetMethodInfo(), recorder); // We pass the recorded transition steps back to the caller: transitionChain = recorder.GetRecordedTransitionChain(); } } }
///<summary> /// Retrieves the super state (parent state) of the specified /// state by sending it the empty signal. ///</summary> private MethodInfo GetSuperStateMethod(MethodInfo stateMethod) { QState superState = (QState)stateMethod.Invoke(this, new object[] { new QEvent((int)QSignals.Empty) }); if (superState != null) { return(superState.GetMethodInfo()); } else { return(null); } }
/// <summary> /// Determines whether the state machine is in the state specified by <see paramref="inquiredState"/>. /// </summary> /// <param name="inquiredState">The state to check for.</param> /// <returns> /// <see langword="true"/> if the state machine is in the specified state; /// <see langword="false"/> otherwise. /// </returns> /// <remarks> /// If the currently active state of a hierarchical state machine is s then it is in the /// state s AND all its parent states. /// </remarks> public bool IsInState(QState inquiredState) { MethodInfo stateMethod; for (stateMethod = m_MyStateMethod; stateMethod != null; stateMethod = GetSuperStateMethod(stateMethod)) { if (stateMethod == inquiredState.GetMethodInfo()) // do the states match? { return(true); } } return(false); // no match found }
private MethodInfo Trigger(MethodInfo stateMethod, QSignals qSignal) { var evt = new QEvent((int)qSignal); OnEvent(stateMethod, evt); QState state = (QState)stateMethod.Invoke(this, new object[] { evt }); if (state == null) { return(null); } else { return(state.GetMethodInfo()); } }
/// <summary> /// Dispatches the specified event to this state machine /// </summary> /// <param name="qEvent">The <see cref="IQEvent"/> to dispatch.</param> protected void CoreDispatch(IQEvent qEvent) { // We let the event bubble up the chain until it is handled by a state handler m_MySourceStateMethod = m_MyStateMethod; do { OnEvent(m_MySourceStateMethod, qEvent); QState state = (QState)m_MySourceStateMethod.Invoke(this, new object[] { qEvent }); if (state != null) { m_MySourceStateMethod = state.GetMethodInfo(); } else { m_MySourceStateMethod = null; } } while (m_MySourceStateMethod != null); }
/// <summary> /// Represents the macro Q_INIT in Miro Samek's implementation /// </summary> protected void InitializeState(QState state) { m_MyStateMethod = state.GetMethodInfo(); }