Пример #1
0
 /// <summary>
 /// Constructor for synchronized FSM
 /// </summary>
 /// <param name="synchronized"></param>
 public Fsm( bool synchronized )
     : base(synchronized)
 {
     classInfo = (FsmClassInfo)FsmClassInfo.fsmClassInfoMap[GetType()];
     if ( classInfo == null )
     {
         InitializeFsmClassInfo();
     }
     Debug.Assert( classInfo != null );
 }
Пример #2
0
        /// <summary>
        /// Initializes the class info for an FSM. It is called when 
        /// the construcor is called the first time. This can not be done
        /// in static constructor since derived class must already exist.
        /// Constructing this information at startup time saves a lot of execution
        /// time while dispatching events!
        /// </summary>
        private void InitializeFsmClassInfo()
        {
            Type typeFsm = GetType();
            Debug.Assert( classInfo == null );
            classInfo = new FsmClassInfo();
            classInfo.name = typeFsm.Name;
            FsmClassInfo.fsmClassInfoMap[typeFsm] = classInfo;

            // Check, if client want to use attributes for defining state var and handler
            Object[] fsmCodingAttributes = typeFsm.GetCustomAttributes(typeof(FsmCodingAttribute),true);
            Debug.Assert( fsmCodingAttributes.Length <= 1 );
            if ( fsmCodingAttributes.Length > 0 )
            {
                FsmCodingAttribute attr = (FsmCodingAttribute)fsmCodingAttributes[0];
                classInfo.fsmCodingType = attr.CodingType;
            }

            // get state member variable if available
            MemberInfo[] stateFields;
            if ( classInfo.fsmCodingType == ECodingType.Automatic )
            {
                // No attribute needed, just take the member with the name "state"
                stateFields = typeFsm.GetMember(
                    "state",
                    MemberTypes.Field,
                    BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
            }
            else
            {
                // Find a enum member with the attribute "FsmState"
                stateFields = typeFsm.FindMembers(MemberTypes.Field,
                    BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
                    new MemberFilter(HasFieldAttributeOfType), typeof(FsmStateAttribute));

                // Generate a GetCurrentState method for this FSM class
                // Note: don't know how to implement ....
            }

            // Get all info from state valiable and prepare state info
            FieldInfo stateField;
            FieldInfo[] StateEnums;
            Hashtable stringToStateMap = new Hashtable();
            if ( stateFields.Length > 0 )
            {
                classInfo.hasStates = true;
                // Get transition handlers and state handlers
                // This FSM has a state field, get the filed info of it.
                // Fill a string map with the enumeration value names for faster lookup
                Debug.Assert( stateFields.Length == 1 );
                stateField = (FieldInfo)stateFields[0];
                classInfo.stateEnumType = stateField.FieldType;
                Debug.Assert(classInfo.stateEnumType.IsSubclassOf(typeof(System.Enum)));
                StateEnums = classInfo.stateEnumType.GetFields(
                    BindingFlags.Static|BindingFlags.Public|BindingFlags.NonPublic);
                classInfo.stateInfoArray = new StateInfo[StateEnums.Length];

                foreach ( FieldInfo fieldInfo in StateEnums )
                {
                    int val = (int)fieldInfo.GetValue(null);
                    StateInfo stateInfo = new StateInfo();
                    classInfo.stateInfoArray[val] = stateInfo;
                    Debug.Assert(classInfo.stateInfoArray[val] == stateInfo);
                    stateInfo.name = fieldInfo.Name;
                    stateInfo.transitions = new Hashtable();
                    stringToStateMap.Add(fieldInfo.Name, stateInfo );
                }
            }

            // Get all methods which are candidates for any kind of handlers
            MemberInfo[] handlers = typeFsm.FindMembers(MemberTypes.Method,
                BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
                new MemberFilter(IsValidFsmHandler), null);

            // Loop over all these methods
            foreach ( MemberInfo mi in handlers )
            {
                MethodInfo meth = (MethodInfo)mi;
                StateInfo stateInfo = null;
                if ( classInfo.fsmCodingType == ECodingType.Automatic )
                {
                    // check if it is a state or transition handler
                    bool bIsStateOrTransitionHandler = false;
                    int separatorPos = meth.Name.IndexOf("_");
                    if ( separatorPos >= 0 )
                    {
                        string prefix = meth.Name.Substring(0, separatorPos);
                        stateInfo = (StateInfo)stringToStateMap[prefix];
                        if ( stateInfo != null )
                        {
                            // It is a state or transition handler
                            bIsStateOrTransitionHandler = true;
                        }
                    }

                    if ( bIsStateOrTransitionHandler )
                    {
                        if ( meth.Name.EndsWith("_EntryState") )
                        {
                            Debug.Assert(meth.GetParameters().Length == 2);
                            Debug.Assert(meth.GetParameters()[0].ParameterType == typeof(FsmEvent));
                            Debug.Assert(meth.GetParameters()[1].ParameterType == classInfo.stateEnumType);
                            stateInfo.entryMethod = meth;
                        }
                        else if ( meth.Name.EndsWith("_ExitState") )
                        {
                            Debug.Assert(meth.GetParameters().Length == 1);
                            Debug.Assert(meth.GetParameters()[0].ParameterType == typeof(FsmEvent));
                            stateInfo.exitMethod = meth;
                        }
                        else if ( meth.GetParameters().Length == 1 )
                        {
                            if ( meth.GetParameters()[0].ParameterType == typeof(FsmEvent) )
                            {
                                // it is a default transition
                                stateInfo.defaultTransitionMethod = meth;
                            }
                            else if ( meth.GetParameters()[0].ParameterType.IsSubclassOf(typeof(FsmEvent)) )
                            {
                                // it is a transition
                                Type eventParamType = meth.GetParameters()[0].ParameterType;
                                Debug.Assert( stateInfo.transitions[eventParamType] == null );
                                stateInfo.transitions[eventParamType] = meth;
                            }
                            else
                            {
                                // Do nothing, it is not a FSM method
                            }
                        }
                        else
                        {
                            // Do nothing, it is not a FSM method
                        }
                    }
                    else
                    {
                        if ( meth.GetParameters().Length == 1 &&
                            meth.GetParameters()[0].ParameterType.IsSubclassOf(typeof(FsmEvent))	)
                        {
                            // Its an event handler
                            Type eventParamType = meth.GetParameters()[0].ParameterType;
                            // add [FsmNoHandler] to failing method when asserting here!
                            Debug.Assert( classInfo.eventHandlers[eventParamType] == null );
                            classInfo.eventHandlers[eventParamType] = meth;
                        }
                        else
                        {
                            // Do nothing, it is not a FSM method
                        }
                    }
                }
                else
                {
                    // NOT Automatic, with attributes
                    object[] attribs;

                    // Is it a transition handler ?
                    attribs = mi.GetCustomAttributes(typeof(FsmTransitionHandlerAttribute), false);
                    if ( attribs.Length > 0 )
                    {
                        // yes, it is a transition handler, assign it to state info
                        FsmTransitionHandlerAttribute attrib = (FsmTransitionHandlerAttribute)attribs[0];
                        stateInfo = (StateInfo)stringToStateMap[attrib.FromState];
                        Debug.Assert( stateInfo != null );
                        Type eventParamType = meth.GetParameters()[0].ParameterType;

                        // Is it the default transition handler ?
                        if ( eventParamType == typeof(FsmEvent) )
                        {
                            // Yes, store it
                            stateInfo.defaultTransitionMethod = meth;
                        }
                        else
                        {
                            // It is a normal transiton handler
                            Debug.Assert( eventParamType.IsSubclassOf(typeof(FsmEvent)) );
                            Debug.Assert( stateInfo.transitions[eventParamType] == null );
                            stateInfo.transitions[eventParamType] = meth;
                        }
                    }
                    else
                    {
                        attribs = mi.GetCustomAttributes(typeof(FsmStateHandlerAttribute), false);
                        if ( attribs.Length > 0 )
                        {
                            // yes, it is a state handler
                            FsmStateHandlerAttribute attrib = (FsmStateHandlerAttribute)attribs[0];
                            stateInfo = (StateInfo)stringToStateMap[attrib.State];
                            Debug.Assert( stateInfo != null );
                            if ( attrib.HandlerType == EStateHandlerType.Entry )
                            {
                                Debug.Assert( meth.GetParameters().Length == 2 );
                                Debug.Assert( meth.GetParameters()[0].ParameterType == typeof(FsmEvent));
                                Debug.Assert( meth.GetParameters()[1].ParameterType == classInfo.stateEnumType);
                                Debug.Assert( stateInfo.entryMethod == null );
                                stateInfo.entryMethod = meth;
                            }
                            else if ( attrib.HandlerType == EStateHandlerType.Exit )
                            {
                                Debug.Assert( meth.GetParameters().Length == 1 );
                                Debug.Assert( meth.GetParameters()[0].ParameterType == typeof(FsmEvent));
                                Debug.Assert( stateInfo.exitMethod == null );
                                stateInfo.exitMethod = meth;
                            }
                            else
                            {
                                Trace.WriteLine( "Unexpected State Handler attribute value" );
                                Debug.Assert( false );
                            }
                        }
                        else
                        {
                            // it is neither a transition nor a state handler
                            // Is it a event handler
                            attribs = mi.GetCustomAttributes(typeof(FsmEventHandlerAttribute), false);
                            if ( attribs.Length > 0 )
                            {
                                // yes, it is an event handler
                                FsmEventHandlerAttribute attrib = (FsmEventHandlerAttribute)attribs[0];
                                Type eventParamType = meth.GetParameters()[0].ParameterType;
                                Debug.Assert( classInfo.eventHandlers[eventParamType] == null );
                                Debug.Assert( eventParamType.IsSubclassOf(typeof(FsmEvent)) );
                                classInfo.eventHandlers[eventParamType] = meth;
                            }
                        }
                    }
                }
            }
        }