C# 中的简单状态机示例?
更新:
再次感谢您提供的示例,它们非常有帮助,并且以下内容并不是我的意思 夺走他们的任何东西。
据我了解,当前给出的示例不是吗?状态机,只是我们通常理解的状态机的一半?
从某种意义上说,这些示例确实改变了状态,但这仅通过改变变量的值来表示(并允许不同的值在不同的状态下发生变化),而通常情况下,状态机也应该改变其行为,并且行为不(仅)意思是允许变量根据状态改变不同的值,但意思是允许针对不同的状态执行不同的方法。
或者我对状态机及其常见用途有误解吗?
原始问题:
我发现了关于状态机和状态机的讨论C# 中的迭代器块 以及为 C# 创建状态机等的工具,所以我发现了很多抽象的东西,但作为一个菜鸟,所有这些都有点令人困惑。
因此,如果有人能够提供一个 C# 源代码示例,该示例可以实现一个可能具有 3,4 个状态的简单状态机,以便了解其要点,那就太好了。
Update:
Again thanks for the examples, they have been very helpful and with the following, I don't mean
to take anything away from them.
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.
Or do I have a misconception of state machines and their common use?
Original question:
I found this discussion about state machines & iterator blocks in c# and tools to create state machines and whatnot for C#, so I found a lot of abstract stuff but as a noob, all of this is a little confusing.
So it would be great if someone could provide a C# source code-example that realizes a simple state machine with perhaps 3,4 states, just to get the gist of it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
让我们从这个简单的状态图开始:
我们有:
您可以通过多种方式将其转换为 C#,例如对当前状态和命令执行 switch 语句,或者在转换表中查找转换。对于这个简单的状态机,我更喜欢使用转换表,它很容易使用
字典
来表示:根据个人喜好,我喜欢使用
GetNext<来设计我的状态机/code> 函数确定性返回下一个状态,以及
MoveNext
改变状态机的函数。Let's start with this simple state diagram:
We have:
You can convert this to C# in a handful of ways, such as performing a switch statement on the current state and command, or looking up transitions in a transition table. For this simple state machine, I prefer a transition table, which is very easy to represent using a
Dictionary
:As a matter of personal preference, I like to design my state machines with a
GetNext
function to return the next state deterministically, and aMoveNext
function to mutate the state machine.您可能想使用现有的开源有限状态机之一。例如 bbv.Common.StateMachine 位于 http://code.google.com/p/bbvcommon /wiki/状态机。它具有非常直观流畅的语法和许多功能,例如进入/退出操作、转换操作、防护、分层、被动实现(在调用者的线程上执行)和主动实现(fsm 运行的自己的线程,事件被添加到队列中)。
以 Juliets 为例,状态机的定义变得非常简单:
更新:项目位置已移至:https://github.com/appccelerate/statemachine
You might want to use one of the existing open source Finite State Machines. E.g. bbv.Common.StateMachine found at http://code.google.com/p/bbvcommon/wiki/StateMachine. It has a very intuitive fluent syntax and a lot of features such as, enter/exit actions, transition actions, guards, hierarchical, passive implementation (executed on the thread of the caller) and active implementation (own thread on which the fsm runs, events are added to a queue).
Taking Juliets example the definition for the state machine gets very easy:
Update: The project location has moved to: https://github.com/appccelerate/statemachine
这是一个非常经典的有限状态机的示例,对一个非常简化的电子设备(如电视)进行建模
Here's an example of a very classic finite state machine, modelling a very simplified electronic device (like a TV)
这里有一些无耻的自我推销,但不久前我创建了一个名为 YieldMachine 的库,它允许有限的复杂性状态机以非常干净和简单的方式描述。例如,考虑一盏灯:
请注意,该状态机有 2 个触发器和 3 个状态。在 YieldMachine 代码中,我们为所有与状态相关的行为编写一个方法,其中我们对每个状态使用
goto
进行了可怕的暴行。触发器成为Action
类型的属性或字段,并用名为Trigger
的属性进行修饰。我在下面评论了第一个状态及其转换的代码;接下来的状态遵循相同的模式。又短又好,嗯!
只需通过向其发送触发器即可控制此状态机:
为了澄清起见,我在第一个状态中添加了一些注释,以帮助您了解如何使用它。
这是可行的,因为 C# 编译器实际上在内部为每个使用
yield return
的方法创建了一个状态机。此构造通常用于延迟创建数据序列,但在这种情况下,我们实际上对返回的序列(无论如何都是空值)不感兴趣,而是对在幕后创建的状态行为感兴趣。StateMachine
基类对构造进行一些反射,以将代码分配给每个[Trigger]
操作,这会设置Trigger
成员并移动状态机向前。但您实际上并不需要了解其内部原理就可以使用它。
Some shameless self-promo here, but a while ago I created a library called YieldMachine which allows a limited-complexity state machine to be described in a very clean and simple way. For example, consider a lamp:
Notice that this state machine has 2 triggers and 3 states. In YieldMachine code, we write a single method for all state-related behavior, in which we commit the horrible atrocity of using
goto
for each state. A trigger becomes a property or field of typeAction
, decorated with an attribute calledTrigger
. I've commented the code of the first state and its transitions below; the next states follow the same pattern.Short and nice, eh!
This state machine is controlled simply by sending triggers to it:
Just to clarify, I've added some comments to the first state to help you understand how to use this.
This works because the C# compiler actually created a state machine internally for each method that uses
yield return
. This construct is usually used to lazily create sequences of data, but in this case we're not actually interested in the returned sequence (which is all nulls anyway), but in the state behaviour that gets created under the hood.The
StateMachine
base class does some reflection on construction to assign code to each[Trigger]
action, which sets theTrigger
member and moves the state machine forward.But you don't really need to understand the internals to be able to use it.
您可以编写一个迭代器块,让您以编排的方式执行代码块。代码块的分解方式实际上不必与任何内容相对应,而只是您想要如何编码。例如:
在这种情况下,当您调用 CountToTen 时,实际上还没有执行任何操作。您得到的实际上是一个状态机生成器,您可以为其创建状态机的新实例。您可以通过调用 GetEnumerator() 来完成此操作。生成的 IEnumerator 实际上是一个状态机,您可以通过调用 MoveNext(...) 来驱动它。
因此,在此示例中,第一次调用 MoveNext(...) 时,您将看到“1”写入控制台,下次调用 MoveNext(...) 时,您将看到 2、3、4 和然后是 5、6、7,然后是 8,然后是 9、10。正如您所看到的,这是一个有用的机制,可以安排事情如何发生。
You can code an iterator block that lets you execute a code block in an orchestrated fashion. How the code block is broken up really doesn't have to correspond to anything, it's just how you want to code it. For example:
In this case, when you call CountToTen, nothing actually executes, yet. What you get is effectively a state machine generator, for which you can create a new instance of the state machine. You do this by calling GetEnumerator(). The resulting IEnumerator is effectively a state machine that you can drive by calling MoveNext(...).
Thus, in this example, the first time you call MoveNext(...) you will see "1" written to the console, and the next time you call MoveNext(...) you will see 2, 3, 4, and then 5, 6, 7 and then 8, and then 9, 10. As you can see, it's a useful mechanism for orchestrating how things should occur.
记住状态机是一种抽象,您不需要特定的工具来创建状态机,但工具可能很有用,这一点很有用。
例如,您可以实现一个具有以下功能的状态机:
该机器将寻找海鸥并尝试用水气球击中它们。如果它错过了,它会尝试发射一个直到它击中(可以满足一些现实的期望;)),否则它会在控制台中幸灾乐祸。它会继续捕猎,直到摆脱海鸥的骚扰。
每个功能对应每个状态;不显示开始和结束(或接受)状态。不过,其中的状态可能比函数建模的状态还要多。例如,在发射气球之后,机器实际上处于与之前不同的状态,但我认为这种区分是不切实际的。
一种常见的方式是使用类来表示状态,然后以不同的方式将它们连接起来。
It's useful to remember that state machines are an abstraction, and you don't need particular tools to create one, however tools can be useful.
You can for example realise a state machine with functions:
This machine would hunt for gulls and try to hit them with water balloons. If it misses it will try firing one until it hits (could do with some realistic expectations ;)), otherwise it will gloat in the console. It continues to hunt until it's out of gulls to harass.
Each function corresponds to each state; the start and end (or accept) states are not shown. There are probably more states in there than modelled by the functions though. For example after firing the balloon the machine is really in another state than it was before it, but I decided this distinction was impractical to make.
A common way is to use classes to represent states, and then connect them in different ways.
在网上找到了这个很棒的教程,它帮助我了解了有限状态机。
http://gamedevelopment.tutsplus.com/ tutorials/finite-state-machines-theory-and-implementation--gamedev-11867
本教程与语言无关,因此可以轻松适应您的 C# 需求。
此外,所使用的示例(蚂蚁寻找食物)很容易理解。
来自教程:
Found this great tutorial online and it helped me wrap my head around finite state machines.
http://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation--gamedev-11867
The tutorial is language agnostic, so it can easily be adapted to your C# needs.
Also, the example used (an ant looking for food) is easy to understand.
From the tutorial:
我在这里发布另一个答案,因为这是从不同角度来看的状态机;非常直观。
我原来的答案是经典的命令式代码。我认为它的代码非常直观,因为数组使状态机的可视化变得简单。缺点是您必须编写所有这些内容。 Remos 的答案减轻了编写样板代码的工作量,但远不那么直观。还有第三种选择;真正绘制状态机。
如果您使用 .NET 并且可以以运行时版本 4 为目标,那么您可以选择使用工作流的状态机活动。这些本质上可以让您绘制状态机(就像 Juliet 的图表一样)并让 WF 运行时执行给你的。
请参阅 MSDN 文章 使用以下命令构建状态机Windows Workflow Foundation 了解更多详细信息,以及此CodePlex 网站 获取最新版本。
当我以 .NET 为目标时,我总是更喜欢这个选项,因为它很容易向非程序员查看、更改和解释;正如他们所说,图片胜过千言万语!
I'm posting another answer here as this is state machines from a different perspective; very visual.
My original answer is classic imperative code. I think its quite visual as code goes because of the array which makes visualizing the state machine simple. The downside is you have to write all this. Remos's answer alleviates the effort of writing the boiler-plate code but is far less visual. There is the third alternative; really drawing the state machine.
If you are using .NET and can target version 4 of the run time then you have the option of using workflow's state machine activities. These in essence let you draw the state machine (much as in Juliet's diagram) and have the WF run-time execute it for you.
See the MSDN article Building State Machines with Windows Workflow Foundation for more details, and this CodePlex site for the latest version.
That's the option I would always prefer when targeting .NET because its easy to see, change and explain to non programmers; pictures are worth a thousand words as they say!
今天我深入研究了状态设计模式。
我做了并测试了 ThreadState,它等于 (+/-) C# 中的线程,如 C# 中的线程
您可以轻松添加新状态,配置从一种状态移动到其他非常简单,因为它封装在状态实现中
实现并使用于: 按状态设计模式实现 .NET ThreadState
Today i deep in State Design Pattern.
I did and tested ThreadState, which equal (+/-) to Threading in C#, as described in picture from Threading in C#
You can easly add new states, configure moves from one state to other is very easy becouse it incapsulated in state implementation
Implementation and using at: Implements .NET ThreadState by State Design Pattern
我还没有尝试在 C# 中实现 FSM,但这些听起来(或看起来)对于我过去在 C 或 ASM 等低级语言中处理 FSM 的方式来说都非常复杂。
我相信我一直知道的方法被称为“迭代循环”。在其中,您本质上有一个“while”循环,它根据事件(中断)定期退出,然后再次返回到主循环。
在中断处理程序中,您将传递一个 CurrentState 并返回一个 NextState,然后它会覆盖主循环中的 CurrentState 变量。您可以无限地执行此操作,直到程序关闭(或微控制器重置)。
与我认为的 FSM 的实现方式相比,我看到的其他答案看起来都非常复杂;它的美妙之处在于它的简单性,FSM 可能非常复杂,有很多很多的状态和转换,但它们允许复杂的过程很容易分解和消化。
我意识到我的回答不应包含其他问题,但我不得不问:为什么这些其他提议的解决方案看起来如此复杂?
它们似乎类似于用大锤敲击小钉子。
I haven't tried implementing a FSM in C# yet, but these all sound (or look) very complicated to the way I handled FSM's in the past in low-level languages like C or ASM.
I believe the method I've always known is called something like an "Iterative Loop". In it, you essentially have a 'while' loop that periodically exits based on events (interrupts), then returns to the main loop again.
Within the interrupt handlers, you would pass a CurrentState and return a NextState, which then overwrites the CurrentState variable in the main loop. You do this ad infinitum until the program closes (or the microcontroller resets).
What I'm seeing other answers all look very complicated compared with how a FSM is, in my mind, intended to be implemented; its beauty lies in its simplicity and FSM can be very complicated with many, many states and transitions, but they allow complicated process to be easily broken down and digested.
I realize my response shouldn't include another question, but I am forced to ask: why do these other proposed solutions appear to be so complicated?
They seem to be akin to hitting a small nail with a giant sledge hammer.
不确定我是否错过了重点,但我认为这里的答案都不是“简单”的状态机。我通常所说的简单状态机是使用内部带有开关的循环。这就是我们在大学的PLC/微芯片编程或C/C++编程中使用的方法。
优点:
缺点:
它看起来像这样:
如果它确实应该是一个状态机,您可以在其中调用根据您所处的状态做出不同反应的方法:状态设计模式是更好的方法
Not sure whether I miss the point, but I think none of the answers here are "simple" state machines. What i usually call a simple state machine is using a loop with a switch inside. That is what we used in PLC / microchip programming or in C/C++ programming at the university.
advantages:
disadvantages:
It looked like that:
if it should be really a state machine on which you call methods which react depending on which state you are in differently: state design pattern is the better approach
我用朱丽叶的代码制作了这个通用状态机。它对我来说非常棒。
这些是好处:
TState
和TCommand
在代码中创建新的状态机,TransitionResult
以获得更多 通过代码:
这是 TryGetNext 方法的返回类型:
如何使用:
这是您如何从泛型类创建
OnlineDiscountStateMachine
:定义一个枚举
OnlineDiscountState
表示其状态,枚举OnlineDiscountCommand
表示其命令。使用这两个枚举定义从泛型类派生的类
OnlineDiscountStateMachine
从
base(OnlineDiscountState.InitialState)
派生构造函数,以便初始状态为设置为OnlineDiscountState.InitialState
根据需要多次使用
AddTransition
使用派生状态机
I made this generic state machine out of Juliet's code. It's working awesome for me.
These are the benefits:
TState
andTCommand
,TransitionResult<TState>
to have more control over the output results of[Try]GetNext()
methodsStateTransition
only throughAddTransition(TState, TCommand, TState)
making it easier to work with itCode:
This is the return type of TryGetNext method:
How to use:
This is how you can create a
OnlineDiscountStateMachine
from the generic class:Define an enum
OnlineDiscountState
for its states and an enumOnlineDiscountCommand
for its commands.Define a class
OnlineDiscountStateMachine
derived from the generic class using those two enumsDerive the constructor from
base(OnlineDiscountState.InitialState)
so that the initial state is set toOnlineDiscountState.InitialState
Use
AddTransition
as many times as neededuse the derived state machine
StatePattern 怎么样?这符合您的需求吗?
我认为它的背景相关,但它肯定值得一试。
http://en.wikipedia.org/wiki/State_pattern
这让您的州决定去哪里而不是“对象”类。
布鲁诺
What a bout StatePattern. Does that fit your needs?
I think its context related, but its worth a shot for sure.
http://en.wikipedia.org/wiki/State_pattern
This let your states decide where to go and not the "object" class.
Bruno
在我看来,状态机不仅用于改变状态,而且(非常重要)用于处理特定状态内的触发器/事件。如果你想更好地理解状态机设计模式,可以在Head First Design一书中找到很好的描述模式,第 320 页。
它不仅涉及变量内的状态,还涉及处理不同状态内的触发器。很棒的一章(不,我提到这一点是免费的:-),其中只包含一个易于理解的解释。
In my opinion a state machine is not only meant for changing states but also (very important) for handling triggers/events within a specific state. If you want to understand state machine design pattern better, a good description can be found within the book Head First Design Patterns, page 320.
It is not only about the states within variables but also about handling triggers within the different states. Great chapter (and no, there is no fee for me in mentioning this :-) which contains just an easy to understand explanation.
我刚刚贡献了这个:
https://code。 google.com/p/ysharp/source/browse/#svn%2Ftrunk%2FStateMachinesPoC
这是演示直接和间接发送命令的示例之一,状态为 IObserver(信号),从而响应信号源, IObservable(of signal):
注意:这个例子相当人为,主要是为了演示一些正交特征。很少需要使用 CRTP 通过完整的类来实现状态值域本身(请参阅:http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern )就像这样。
状态值域),针对相同的状态机,并使用相同的测试用例:
这是一个肯定更简单且可能更常见的实现用例(使用简单的枚举类型作为 google.com/p/ysharp/source/browse/trunk/StateMachinesPoC/WatchingTVSample.cs" rel="nofollow noreferrer">https://code.google.com/p/ysharp/source/browse/trunk/StateMachinesPoC/WatchingTVSample .cs
'HTH
I've just contributed this:
https://code.google.com/p/ysharp/source/browse/#svn%2Ftrunk%2FStateMachinesPoC
Here's one of the examples demoing direct and indirect sending of commands, with states as IObserver(of signal), thus responders to a signal source, IObservable(of signal):
Note : this example is rather artificial and mostly meant to demo a number of orthogonal features. There should seldomly be a real need to implement the state value domain itself by a full blown class, using the CRTP ( see : http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern ) like this.
Here's for a certainly simpler and likely much more common implementation use case (using a simple enum type as the states value domain), for the same state machine, and with the same test case :
https://code.google.com/p/ysharp/source/browse/trunk/StateMachinesPoC/WatchingTVSample.cs
'HTH
FiniteStateMachine 是一个简单状态机,用 C# 编写 链接
使用我的库 FiniteStateMachine 的优点:
下载 DLL 下载
LINQPad 上的示例:
FiniteStateMachine is a Simple State Machine, written in C# Link
Advantages tu use my library FiniteStateMachine:
Download DLL Download
Example on LINQPad:
我会推荐 state.cs。我个人使用过 state.js(JavaScript 版本)并且对它非常满意。该 C# 版本的工作方式类似。
您实例化状态:
您实例化一些转换:
您定义状态和转换上的操作:(
几乎)就是这样。请访问网站了解更多信息。
I would recommend state.cs. I personally used state.js (the JavaScript version) and am very happy with it. That C# version works in a similar way.
You instantiate states:
You instantiate some transitions:
You define actions on states and transitions:
And that's (pretty much) it. Look at the website for more information.
NuGet 中有 2 个流行的状态机包。
Appccelerate.StateMachine(13.6K 下载量 + 3.82K 旧版本 (bbv.Common.StateMachine))
< a href="https://github.com/OmerMor/StateMachineToolkit" rel="nofollow noreferrer">StateMachineToolkit (1.56K 下载)
Appccelerate 库有良好的文档,但它不支持 .NET 4 ,所以我为我的项目选择了 StateMachineToolkit。
There are 2 popular state machine packages in NuGet.
Appccelerate.StateMachine (13.6K downloads + 3.82K of legacy version (bbv.Common.StateMachine))
StateMachineToolkit (1.56K downloads)
The Appccelerate lib has good documentation, but it does not support .NET 4, so I chose StateMachineToolkit for my project.
此仓库中的其他替代方案 https://github.com/lingkodsoft/StateBliss
使用流畅的语法,支持触发器。
Other alternative in this repo https://github.com/lingkodsoft/StateBliss
used fluent syntax, supports triggers.
我的列表还有一个状态机: https://github.com/IanMercer/Abodit.StateMachine< /a>
除了具有进入和退出操作以及每次转换的操作的简单状态之外,该状态还设计用于异步代码。它还支持分层状态和复合状态机。所以并不是真的“简单”,但在使用中,对状态和转换进行编码非常容易。
与其他的不同,它还支持时间转换,因此可以轻松地在给定时间段
After
或给定时间At
转换到不同的状态。One more state machine for the list, mine: https://github.com/IanMercer/Abodit.StateMachine
In addition to simple states with entry and exit actions, and actions on each transition, this one is designed for use in async code. It also supports hierarchical states and compound state machines. So not really 'simple' but in use it's quite easy to code states and transitions.
Unlike others it also supports temporal transitions so it's easy to transition to a different state
After
a given period orAt
a given time.我构建了一个 Nuget 库,它实现了一个简单而强大的状态机并可在 DI 中注入。您可以从这里查看 Nuget - 状态机
I've built a Nuget library that implements a simple and powerful state machine and injectable in DI. You can check it from here Nuget - State Machine
你可以使用我的解决方案,这是最方便的方法。它也是免费的。
通过三个步骤创建状态机:
1.在中创建方案节点编辑器
You can use my solution, this is the most convenient way. It’s also free.
Create state machine in three steps :
1. Create scheme in node editor???? and load it in your project using library????
2. Describe your app logic on events⚡
3. Run the state machine????
Links:
Node editor: https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor
Library: https://github.com/SimpleStateMachine/SimpleStateMachineLibrary