C# 使用“yield”关键字实现状态机
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1194853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
implementing a state machine using the "yield" keyword
提问by Matt Warren
Is it feasible to use the yield keyword to implement a simple state machine as shown here. To me it looks like the C# compiler has done the hard work for you as it internally implements a state machine to make the yield statement work.
使用 yield 关键字来实现一个简单的状态机是否可行,如下所示。在我看来,C# 编译器已经为您完成了艰苦的工作,因为它在内部实现了一个状态机来使 yield 语句工作。
Can you piggy-back on top of the work the compiler is already doing and get it to implement most of the state machine for you?
您能否利用编译器已经在做的工作并让它为您实现大部分状态机?
Has anyone done this, is it technically possible?
有没有人这样做过,技术上可行吗?
采纳答案by Eric Lippert
It's feasible but it is a bad idea. Iterator blocks were created to help you write custom iterators for collections, not for solving the general-purpose problem of implementing state machines.
这是可行的,但这是一个坏主意。创建迭代器块是为了帮助您为集合编写自定义迭代器,而不是用于解决实现状态机的通用问题。
If you want to write a state machine, just write a state machine. It's not hard. If you want to write a lot of state machines, write a library of useful helper methods that let you cleanly represent state machines, and then use your library. But don't abuse a language construct intended for something completely different that just happens to use state machines as an implementation detail. That makes your state machine code hard to read, understand, debug, maintain and extend.
如果要编写状态机,只需编写状态机即可。这并不难。如果您想编写大量状态机,请编写一个有用的辅助方法库,让您可以干净地表示状态机,然后使用您的库。但是不要滥用用于完全不同的语言结构,而这些语言结构恰好将状态机用作实现细节。这使您的状态机代码难以阅读、理解、调试、维护和扩展。
(And incidentally, I did a double-take when reading your name. One of the designers of C# is also named Matt Warren!)
(顺便说一句,当我读到你的名字时,我做了一个双重检查。C# 的一位设计师也叫 Matt Warren!)
回答by Mehrdad Afshari
Yes, it's absolutely possible and easy to do. You can enjoy using control flow constructs (for
, foreach
, while
, ... goto
(using goto
particularly suits this scenario ;))) along with yield
s to build one.
是的,这绝对有可能而且很容易做到。您可以享受使用控制流结构 ( for
, foreach
, while
, ... goto
(使用goto
特别适合这种情况;))) 和yield
s 来构建一个。
IEnumerator<State> StateMachine
(Func<int> currentInput /* gets current input from IO port */,
Func<int> currentOutput) {
for (;;) {
if ((currentInput() & 1) == 0)
yield return new State("Ready");
else {
if (...) {
yield return new State("Expecting more data");
SendOutput(currentOutput());
while ((currentInput() & 2) != 0) // while device busy
yield return new State("Busy");
else if (...) { ... }
}
}
}
// consumer:
int data;
var fsm = StateMachine(ReadFromIOPort, () => data);
// ...
while (fsm.Current != "Expecting more data")
fsm.MoveNext();
data = 100;
fsm.MoveNext();
回答by Jon Skeet
Iterator blocks do indeed implement state machines, but the tricky bit is getting the next input. How are you going to know where to move next? I guess you could have some sort of shared "current transition" variable, but that's somewhat icky.
迭代器块确实实现了状态机,但棘手的一点是获取下一个输入。你怎么知道下一步要搬到哪里?我想你可以有某种共享的“当前转换”变量,但这有点令人讨厌。
If you don't need any input (e.g. your state machine is just cycling between states) then it's easy, but that's not the interesting kind :)
如果您不需要任何输入(例如您的状态机只是在状态之间循环)那么很容易,但这不是有趣的类型:)
Can you describe the kind of state machine you're interested in?
您能描述一下您感兴趣的状态机类型吗?
回答by Michael Stum
While this is not a state machine in the classical sense, the article about Iterator-based Micro Threadinguses yield creatively for state-based actions.
虽然这不是经典意义上的状态机,但关于基于迭代器的微线程的文章创造性地将 yield 用于基于状态的操作。
IEnumerable Patrol ()
{
while (alive){
if (CanSeeTarget ()) {
yield return Attack ();
} else if (InReloadStation){
Signal signal = AnimateReload ();
yield return signal;
} else {
MoveTowardsNextWayPoint ();
yield return TimeSpan.FromSeconds (1);
};
}
yield break;
}