Hierarchy XML Based C# Statemachine Generator
Introduction
This article discusses how to create hierarchical statemachines based in XML with C# codebehind.
Purpose
Statemachines allow one to represent a problem in a concrete and manageable form that generally has a common solution. The Statemachine code allows one to write a hierarchical based statemachine using XML and generate a corresponding C# code file representing the statemachine with all the semantics needed to execute the statemachine.
Creating a Statemachine
The majority of code to use the statemachine is simply writing it in XML:
<StateMachines name="<NamespaceName>" xmlns="StateMachines">
<StateMachine name="<ClassName>">
<States>
<State name="<StateName>"/>
</States>
<Events>
<Event name="<EventName>"/>
</Events>
<Transitions>
<Transition from="<StateName>"
to="<StateName>" trigger="<EventName>"/>
</Transitions>
</StateMachine>
</StateMachines>
A State
element can be another StateMachine
with the exact same format. Correct XML formatting is provided through a schema but valid references are not checked. The following C# code is generated from the XML.
using StateMachines;
namespace StateMachines.NamespaceName
{
public partial class ClassName :
StateMachine<ClassName.States, ClassName.Events, ClassName.Transitions>
{
public enum States
{
StateName
}
public enum Events
{
EventName
}
public enum Transitions
{
EventName__StateName_StateName
}
public ClassName()
{
_States[(int)States.StateName] =
(this.New(this, States.StateName));
InitialState = _States[(int)States.StateName];
_currentState = InitialState;
_Transitions[(int)Transitions.EventName__StateName_StateName] =
new Transition<States, Events, Transitions>
(States.StateName, States.StateName, Events.EventName);
_Transitions[(int)
Transitions.EventName__StateName_StateName].Conditions =
new Condition(() => { return true; });
}
public new void Fire(ClassName.Events Event, params object[] args)
{
switch(Event)
{
case Events.EventName:
if (_Transitions[(int)Transitions.EventName__
StateName_StateName].Eval())
{
CurrentState =
_States[(int)States.StateName];
}
break;
}
}
// User defined functions. Must Implement.
// Comment out or remove these declarations when used.
}
}
To use the code, one simply has to instantiate the statemachine, add handlers to its events, then fire them. To generate the statemachine, you must add the file to the StateMachine.tt
parser.
States
States are objects representing the states in a statemachine. They cannot be instantiated by anything but the StateMachine and have low weight. A Statemachine itself is a State.
Events
Standard OnEnter
and OnLeave
events exist for all states.
Conditionals
Each transition can have an optional set of conditions that must be passed for the transition to take place. This is to reduce the complexity to setting up complex conditions. A transition may have a hierarchical conditional block that will be evaluated before a transition takes place.
<Transitions>
<Transition from="<StateName>" to="<StateName>" trigger="<EventName>">
<Conditions op="<OperationType>">
<Condition name="<ConditionName" op="<OperationType>">
</Conditions>
</Transition>
</Transitions>
<Conditions>
adds a block of conditions and maybe nested. A <Condition>
references a method in the class by "ConditionName
" and op
is the operation on how to combine the condition.
Conclusion
The usefulness of this code is to reduce all the boilerplate code required in implementing the statemachine along with the type safety of C#.
The files required in the project are:
- StateMachine.cs
- StateMachineGen.tt
- StateMachine.xsd
History
- v0.5 - First release
发表评论
6GRJWN Thanks again for the blog.Really looking forward to read more. Much obliged.