Включает ли С# конечные конечные машины?

Недавно я прочитал о библиотеке boost::statechart (конечные автоматы), и мне понравилась эта концепция.

Есть ли у С# аналогичный механизм? Или он может быть реализован с использованием определенного шаблона проектирования?

Ответ 1

Да, С# имеет блоки итератора, которые являются авторами состояний, сгенерированными компилятором.

Если вы хотите реализовать свой собственный конечный автомат, вы можете создавать пользовательские реализации интерфейсов IEnumerable<T> и IEnumerator<T>.

Оба этих подхода выделяют реализацию .NET Framework шаблон итератора.

Ответ 3

Workflow Foundation (.NET 3.0) имеет рабочий процесс конечного автомата. 4.0 не имеет точно такой же вещи в настоящее время, но вы можете определенно создать рабочий процесс конечного автомата с помощью 4.0.

Ответ 4

Я поддерживаю проект с открытым исходным кодом, который реализует (помимо прочего) общий конечный конечный автомат для .NET. Он построен поверх QuickGraph, поэтому вы получаете множество алгоритмов графического анализа бесплатно.

Подробнее о проекте см. на этой странице, а именно " Jolt.Automata: Finite State Machines" для получения дополнительной информации об этой функции.

Ответ 6

То, что подходит к FSM, - это рабочие процессы в .NET 3.5, однако рабочие процессы не являются точно FSM.

Сила использования FSM заключается в том, что вы можете создать в своем коде явно, имея меньше шансов на создание ошибок. Кроме того, конечно, некоторые системы являются FSM по своей природе, поэтому более естественно их кодировать так.

Ответ 7

Windows Workflow Foundation (WF), который является частью библиотеки базового класса в версиях 3.0 и 3.5, включает в себя проект рабочего процесса в государственном компьютере для управления государственными компьютерами для ваших приложений.

Они полностью переписали рабочий процесс для предстоящей версии 4.0, а новые классы WF 4.0 не поддерживают государственные машины, но все классы 3.0/3.5 по-прежнему полностью поддерживаются в версии 4.0.

Ответ 8

Я написал библиотеку с открытым исходным кодом под названием YieldMachine, которая использует преимущества блоков итератора, чтобы упростить запись состояний машин.

Я объяснил это более подробно в этом ответе.

Ответ 9

Возможно, вы можете найти Floomeen полезным. Это библиотека.Net Standard для создания конечных автоматов.

Найди его на Нугете. Используйте простой API Fluent для описания рабочих процессов.

Ответ 10

Другая альтернатива в этом репо https://github.com/lingkodsoft/StateBliss используется свободный синтаксис, поддерживает триггеры.

    public class BasicTests
    {
        [Fact]
        public void Tests()
        {
            // Arrange
            StateMachineManager.Register(new [] { typeof(BasicTests).Assembly }); //Register at bootstrap of your application, i.e. Startup
            var currentState = AuthenticationState.Unauthenticated;
            var nextState = AuthenticationState.Authenticated;
            var data = new Dictionary<string, object>();

            // Act
            var changeInfo = StateMachineManager.Trigger(currentState, nextState, data);

            // Assert
            Assert.True(changeInfo.StateChangedSucceeded);
            Assert.Equal("ChangingHandler1", changeInfo.Data["key1"]);
            Assert.Equal("ChangingHandler2", changeInfo.Data["key2"]);
        }

        //this class gets regitered automatically by calling StateMachineManager.Register
        public class AuthenticationStateDefinition : StateDefinition<AuthenticationState>
        {
            public override void Define(IStateFromBuilder<AuthenticationState> builder)
            {
                builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
                    .Changing(this, a => a.ChangingHandler1)
                    .Changed(this, a => a.ChangedHandler1);

                builder.OnEntering(AuthenticationState.Authenticated, this, a => a.OnEnteringHandler1);
                builder.OnEntered(AuthenticationState.Authenticated, this, a => a.OnEnteredHandler1);

                builder.OnExiting(AuthenticationState.Unauthenticated, this, a => a.OnExitingHandler1);
                builder.OnExited(AuthenticationState.Authenticated, this, a => a.OnExitedHandler1);

                builder.OnEditing(AuthenticationState.Authenticated, this, a => a.OnEditingHandler1);
                builder.OnEdited(AuthenticationState.Authenticated, this, a => a.OnEditedHandler1);

                builder.ThrowExceptionWhenDiscontinued = true;
            }

            private void ChangingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                var data = changeinfo.DataAs<Dictionary<string, object>>();
                data["key1"] = "ChangingHandler1";
            }

            private void OnEnteringHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                // changeinfo.Continue = false; //this will prevent changing the state
            }

            private void OnEditedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnExitedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnEnteredHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {                
            }

            private void OnEditingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
            }

            private void OnExitingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
            }

            private void ChangedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
            {
            }
        }

        public class AnotherAuthenticationStateDefinition : StateDefinition<AuthenticationState>
        {
            public override void Define(IStateFromBuilder<AuthenticationState> builder)
            {
                builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
                    .Changing(this, a => a.ChangingHandler2);

            }

            private void ChangingHandler2(StateChangeGuardInfo<AuthenticationState> changeinfo)
            {
                var data = changeinfo.DataAs<Dictionary<string, object>>();
                data["key2"] = "ChangingHandler2";
            }
        }
    }

    public enum AuthenticationState
    {
        Unauthenticated,
        Authenticated
    }
}