更新:
再次感谢你的例子,它们对我很有帮助,我并不是说
夺走他们的一切。
Aren't the currently given examples, as far as I understand them & state-machines, only half of what we usually understand by a state-machine?
In the sense that the examples do change state but that's only represented by changing the value of a variable (and allowing different value- changes in different states), while usually, a state machine should also change its behavior, and behavior not (only) in the sense of allowing different value changes for a variable depending on the state, but in the sense of allowing different methods to be executed for different states.
还是我对状态机及其常用用法有误解?
最初的问题:
我发现了关于c#中的状态机和迭代器块的讨论,以及用于创建状态机和c#的工具,所以我发现了很多抽象的东西,但作为一个新手,所有这些都有点令人困惑。
因此,如果有人能提供一个c#源代码-示例,实现一个简单的状态机,可能只有3,4个状态,那就太好了,只是为了了解它的要点。
您可能希望使用现有的开源有限状态机之一。例如,在http://code.google.com/p/bbvcommon/wiki/StateMachine找到的bbv.Common.StateMachine。它具有非常直观流畅的语法和许多特性,如进入/退出操作、转换操作、保护、分层、被动实现(在调用者的线程上执行)和主动实现(fsm运行在自己的线程上,事件被添加到队列中)。
以Juliets为例,状态机的定义非常简单:
var fsm = new PassiveStateMachine<ProcessState, Command>();
fsm.In(ProcessState.Inactive)
.On(Command.Exit).Goto(ProcessState.Terminated).Execute(SomeTransitionAction)
.On(Command.Begin).Goto(ProcessState.Active);
fsm.In(ProcessState.Active)
.ExecuteOnEntry(SomeEntryAction)
.ExecuteOnExit(SomeExitAction)
.On(Command.End).Goto(ProcessState.Inactive)
.On(Command.Pause).Goto(ProcessState.Paused);
fsm.In(ProcessState.Paused)
.On(Command.End).Goto(ProcessState.Inactive).OnlyIf(SomeGuard)
.On(Command.Resume).Goto(ProcessState.Active);
fsm.Initialize(ProcessState.Inactive);
fsm.Start();
fsm.Fire(Command.Begin);
更新:项目位置已移动到:https://github.com/appccelerate/statemachine
您可能希望使用现有的开源有限状态机之一。例如,在http://code.google.com/p/bbvcommon/wiki/StateMachine找到的bbv.Common.StateMachine。它具有非常直观流畅的语法和许多特性,如进入/退出操作、转换操作、保护、分层、被动实现(在调用者的线程上执行)和主动实现(fsm运行在自己的线程上,事件被添加到队列中)。
以Juliets为例,状态机的定义非常简单:
var fsm = new PassiveStateMachine<ProcessState, Command>();
fsm.In(ProcessState.Inactive)
.On(Command.Exit).Goto(ProcessState.Terminated).Execute(SomeTransitionAction)
.On(Command.Begin).Goto(ProcessState.Active);
fsm.In(ProcessState.Active)
.ExecuteOnEntry(SomeEntryAction)
.ExecuteOnExit(SomeExitAction)
.On(Command.End).Goto(ProcessState.Inactive)
.On(Command.Pause).Goto(ProcessState.Paused);
fsm.In(ProcessState.Paused)
.On(Command.End).Goto(ProcessState.Inactive).OnlyIf(SomeGuard)
.On(Command.Resume).Goto(ProcessState.Active);
fsm.Initialize(ProcessState.Inactive);
fsm.Start();
fsm.Fire(Command.Begin);
更新:项目位置已移动到:https://github.com/appccelerate/statemachine
finitestatemmachine是一个简单的状态机,用c# Link编写
使用我的库finitestatemmachine的优点:
定义一个“context”类,向外界呈现一个单独的接口。
定义一个State抽象基类。
将状态机的不同“状态”表示为state基类的派生类。
在适当的State派生类中定义特定于状态的行为。
在“context”类中维护一个指向当前“state”的指针。
要更改状态机的状态,请更改当前的“state”指针。
下载DLL下载
LINQPad上的示例:
void Main()
{
var machine = new SFM.Machine(new StatePaused());
var output = machine.Command("Input_Start", Command.Start);
Console.WriteLine(Command.Start.ToString() + "-> State: " + machine.Current);
Console.WriteLine(output);
output = machine.Command("Input_Pause", Command.Pause);
Console.WriteLine(Command.Pause.ToString() + "-> State: " + machine.Current);
Console.WriteLine(output);
Console.WriteLine("-------------------------------------------------");
}
public enum Command
{
Start,
Pause,
}
public class StateActive : SFM.State
{
public override void Handle(SFM.IContext context)
{
//Gestione parametri
var input = (String)context.Input;
context.Output = input;
//Gestione Navigazione
if ((Command)context.Command == Command.Pause) context.Next = new StatePaused();
if ((Command)context.Command == Command.Start) context.Next = this;
}
}
public class StatePaused : SFM.State
{
public override void Handle(SFM.IContext context)
{
//Gestione parametri
var input = (String)context.Input;
context.Output = input;
//Gestione Navigazione
if ((Command)context.Command == Command.Start) context.Next = new StateActive();
if ((Command)context.Command == Command.Pause) context.Next = this;
}
}
列表的另一个状态机是我的:https://github.com/IanMercer/Abodit.StateMachine
除了具有进入和退出操作的简单状态,以及每个转换上的操作之外,这个是为在异步代码中使用而设计的。它还支持分层状态和复合状态机。所以不是很“简单”,但在使用中,它很容易编码状态和过渡。
static OpenClosedStateMachine()
{
Closed
.When(Fridge.eDoorOpens, (m, s, e, c) => Task.FromResult(Open));
Open
.When(Fridge.eDoorCloses, (m, s, e, c) => Task.FromResult(Closed));
}
不像其他的,它还支持时间转换,所以很容易过渡到不同的状态后,一个给定的时期或在给定的时间。
记住状态机是一种抽象是很有用的,创建状态机不需要特定的工具,但是工具是有用的。
例如,你可以用函数实现一个状态机:
void Hunt(IList<Gull> gulls)
{
if (gulls.Empty())
return;
var target = gulls.First();
TargetAcquired(target, gulls);
}
void TargetAcquired(Gull target, IList<Gull> gulls)
{
var balloon = new WaterBalloon(weightKg: 20);
this.Cannon.Fire(balloon);
if (balloon.Hit)
{
TargetHit(target, gulls);
}
else
TargetMissed(target, gulls);
}
void TargetHit(Gull target, IList<Gull> gulls)
{
Console.WriteLine("Suck on it {0}!", target.Name);
Hunt(gulls);
}
void TargetMissed(Gull target, IList<Gull> gulls)
{
Console.WriteLine("I'll get ya!");
TargetAcquired(target, gulls);
}
这台机器会捕捉海鸥,并试图用水球击中它们。如果它没有命中,它将尝试发射一个直到命中为止(可以有一些现实的期望;)),否则它将在控制台幸灾乐祸。它继续捕猎,直到没有海鸥可以骚扰为止。
每个函数对应于每个状态;没有显示开始和结束(或接受)状态。其中的状态可能比函数所模拟的要多。例如,在发射气球后,机器实际上处于与之前不同的状态,但我认为这种区分是不切实际的。
常用的方法是使用类来表示状态,然后以不同的方式将它们连接起来。