C# でのシンプルなステートマシンの例? 質問する

C# でのシンプルなステートマシンの例? 質問する

アップデート:

再度、例を挙げていただきありがとうございます。非常に役に立ちました。以下では、例を否定するつもりはありません。

現在示されている例とステート マシンは、私が理解している限りでは、ステート マシンについて通常理解しているものの半分にすぎないのではないでしょうか。
例では状態が変わりますが、それは変数の値を変更する (そして異なる状態で異なる値の変更を許可する) ことによってのみ表されます。一方、通常、ステート マシンはその動作も変更する必要があり、その動作は、状態に応じて変数の異なる値の変更を許可するという意味だけでなく、異なる状態で異なるメソッドを実行できるようにするという意味でもあります。

それとも、ステートマシンとその一般的な使用法について誤解しているのでしょうか?


元の質問:

私は次のような議論を見つけましたC# のステートマシンとイテレータブロックC# 用のステート マシンなどを作成するツールもあり、抽象的なものがたくさん見つかりましたが、初心者にとっては、これらすべてが少し混乱します。

したがって、要点を理解するために、おそらく 3、4 個の状態を持つ単純なステート マシンを実現する C# ソース コードの例を誰かが提供してくれるとありがたいです。

ベストアンサー1

この簡単な状態図から始めましょう:

シンプルなステートマシン図

我々は持っています:

  • 4 つの状態 (非アクティブ、アクティブ、一時停止、終了)
  • 5 種類の状態遷移 (開始コマンド、終了コマンド、一時停止コマンド、再開コマンド、終了コマンド)。

これを C# に変換するには、現在の状態とコマンドに対して switch ステートメントを実行したり、遷移テーブルで遷移を検索したりするなど、いくつかの方法があります。この単純なステート マシンでは、 を使用すると非常に簡単に表現できる遷移テーブルを使用することをお勧めしますDictionary

using System;
using System.Collections.Generic;

namespace Juliet
{
    public enum ProcessState
    {
        Inactive,
        Active,
        Paused,
        Terminated
    }

    public enum Command
    {
        Begin,
        End,
        Pause,
        Resume,
        Exit
    }

    public class Process
    {
        class StateTransition
        {
            readonly ProcessState CurrentState;
            readonly Command Command;

            public StateTransition(ProcessState currentState, Command command)
            {
                CurrentState = currentState;
                Command = command;
            }

            public override int GetHashCode()
            {
                return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
            }

            public override bool Equals(object obj)
            {
                StateTransition other = obj as StateTransition;
                return other != null && this.CurrentState == other.CurrentState && this.Command == other.Command;
            }
        }

        Dictionary<StateTransition, ProcessState> transitions;
        public ProcessState CurrentState { get; private set; }

        public Process()
        {
            CurrentState = ProcessState.Inactive;
            transitions = new Dictionary<StateTransition, ProcessState>
            {
                { new StateTransition(ProcessState.Inactive, Command.Exit), ProcessState.Terminated },
                { new StateTransition(ProcessState.Inactive, Command.Begin), ProcessState.Active },
                { new StateTransition(ProcessState.Active, Command.End), ProcessState.Inactive },
                { new StateTransition(ProcessState.Active, Command.Pause), ProcessState.Paused },
                { new StateTransition(ProcessState.Paused, Command.End), ProcessState.Inactive },
                { new StateTransition(ProcessState.Paused, Command.Resume), ProcessState.Active }
            };
        }

        public ProcessState GetNext(Command command)
        {
            StateTransition transition = new StateTransition(CurrentState, command);
            ProcessState nextState;
            if (!transitions.TryGetValue(transition, out nextState))
                throw new Exception("Invalid transition: " + CurrentState + " -> " + command);
            return nextState;
        }

        public ProcessState MoveNext(Command command)
        {
            CurrentState = GetNext(command);
            return CurrentState;
        }
    }


    public class Program
    {
        static void Main(string[] args)
        {
            Process p = new Process();
            Console.WriteLine("Current State = " + p.CurrentState);
            Console.WriteLine("Command.Begin: Current State = " + p.MoveNext(Command.Begin));
            Console.WriteLine("Command.Pause: Current State = " + p.MoveNext(Command.Pause));
            Console.WriteLine("Command.End: Current State = " + p.MoveNext(Command.End));
            Console.WriteLine("Command.Exit: Current State = " + p.MoveNext(Command.Exit));
            Console.ReadLine();
        }
    }
}

個人的な好みとして、私はGetNext次の状態を返す関数を使ってステートマシンを設計するのが好きです。決定論的に、およびMoveNextステートマシンを変更する関数。

おすすめ記事