使用“yield”关键字实现状态机

使用yield关键字来实现这里所示的简单状态机是否可行。 对我来说,看起来C#编译器已经为你完成了艰苦的工作,因为它在内部实现了一个状态机来使yield语句工作。

你可以在编译器已经在做的工作之上捎带并让它为你实现大部分状态机吗?

有没有人这样做,技术上是否可行?

这是可行的,但这是一个坏主意。 创建Iterator块是为了帮助您为集合编写自定义迭代器,而不是为了解决实现状态机的一般目的问题。

如果要编写状态机,只需编写状态机即可。 这并不难。 如果要编写大量状态机,请编写一个有用的辅助方法库,使您可以干净地表示状态机,然后使用您的库。 但是,不要滥用意图完全不同的语言结构,而恰好使用状态机作为实现细节。 这使您的状态机代码难以阅读,理解,调试,维护和扩展。

(顺便说一句,我在读你的名字时做了双重考虑。其中一位C#的设计师也被命名为Matt Warren!)

是的,这绝对可行且容易做到。 您可以享受使用控制流构造( forforeachwhile ,… goto (使用goto特别适合这种情况;)))以及yield s来构建一个。

 IEnumerator StateMachine (Func currentInput /* gets current input from IO port */, Func 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(); 

虽然这不是传统意义上的状态机,但是关于基于迭代器的微线程的文章创造性地用于基于状态的动作。

 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; } 

迭代器块确实实现了状态机,但是棘手的一点是获得下一个输入。 你怎么知道接下来要去哪里? 我想你可能会有某种共享的“当前转换”变量,但这有些蠢。

如果你不需要任何输入(例如你的状态机只是在状态之间循环)那么它很容易,但这不是有趣的类:)

你能描述一下你感兴趣的状态机吗?