/// <summary> /// This is the default handler if there was neither a transition handler nor an event handler /// defined. Overriding this method allows to establish a custom error handler or a default /// event handler defining a default behavior. /// </summary> /// <param name="fsmEvent"></param> protected internal virtual void OnFsmEventDefault(FsmEvent fsmEvent) { // error: There exists neither a transition handler nor an event handler if ( classInfo.hasStates ) { Trace.WriteLine("FSM:" + this.GetType().Name + " Event:" + fsmEvent.GetType().Name + " not handled in state:" + Enum.GetName( classInfo.stateEnumType, GetCurrentState() ) ); } else { Trace.WriteLine("FSM:" + this.GetType().Name + " Event:" + fsmEvent.GetType().Name + " not handled"); } }
/// <summary> /// This is the core event dispatching of the FSM. The FSM looks up the /// curent state and calls the state and transition handlers if they are /// defined. /// Override is possible but not recommended. /// </summary> /// <param name="fsmEvent"></param> protected internal virtual void OnFsmEvent(FsmEvent fsmEvent) { Debug.Assert( classInfo != null ); if ( classInfo.hasStates ) { Int32 currState = GetCurrentState(); // execute transition StateInfo stateInfo1 = classInfo.stateInfoArray[currState]; Debug.Assert( stateInfo1 != null ); MethodInfo methInfoTransition = (MethodInfo)stateInfo1.transitions[fsmEvent.GetType()]; if ( methInfoTransition != null ) { // first execute exit method if ( stateInfo1.exitMethod != null ) { stateInfo1.exitMethod.Invoke(this, new Object[] {fsmEvent}); // it is not allowed to change state in State Exit Handler! Debug.Assert( currState == GetCurrentState() ); } // now execute transition method methInfoTransition.Invoke(this, new Object[] {fsmEvent} ); // on return, FSM has probably a new state int newState = GetCurrentState(); if ( newState != currState ) { // Transition to other state StateInfo stateInfo2 = classInfo.stateInfoArray[newState]; Debug.Assert( stateInfo2 != null ); // Execute Entry state handler of new state if ( stateInfo2.entryMethod != null ) { stateInfo2.entryMethod.Invoke(this, new Object[] {fsmEvent, Enum.ToObject(classInfo.stateEnumType,currState)}); // it is not allowed to change state in State Entry Handler! Debug.Assert( newState == GetCurrentState() ); } } else { // It is the same state --> transition loop if ( stateInfo1.entryMethod != null ) { stateInfo1.entryMethod.Invoke(this, new Object[] {fsmEvent, Enum.ToObject(classInfo.stateEnumType,currState)}); // it is not allowed to change state in State Entry Handler! Debug.Assert( currState == GetCurrentState() ); } } } else { // There is no transition for this event in current state. if ( stateInfo1.defaultTransitionMethod != null ) { stateInfo1.defaultTransitionMethod.Invoke(this, new Object[] {fsmEvent} ); } else { // Try to find an event handler MethodInfo methInfoEvHnd = (MethodInfo)classInfo.eventHandlers[fsmEvent.GetType()]; if ( methInfoEvHnd != null ) { methInfoEvHnd.Invoke(this, new Object[] {fsmEvent} ); } else { // Call default handler OnFsmEventDefault(fsmEvent); } } } } else { // FSM has no states. Therefore event handlers are the only handlers to check. MethodInfo methodInfo = (MethodInfo)classInfo.eventHandlers[fsmEvent.GetType()]; if ( methodInfo != null ) { methodInfo.Invoke(this, new Object[] {fsmEvent} ); } else { // error: No matching event handler available Trace.WriteLine("FSM:" + this.GetType().Name + " Event:" + fsmEvent.GetType().Name + " no event handler found"); } } }