Включает ли С# конечные конечные машины?
Недавно я прочитал о библиотеке boost::statechart
(конечные автоматы), и мне понравилась эта концепция.
Есть ли у С# аналогичный механизм? Или он может быть реализован с использованием определенного шаблона проектирования?
Ответы
Ответ 1
Да, С# имеет блоки итератора, которые являются авторами состояний, сгенерированными компилятором.
Если вы хотите реализовать свой собственный конечный автомат, вы можете создавать пользовательские реализации интерфейсов IEnumerable<T>
и IEnumerator<T>
.
Оба этих подхода выделяют реализацию .NET Framework шаблон итератора.
Ответ 2
.NET 4 Обновление 1 теперь поддерживает его в следующем классе:
System.Activities.Statements.StateMachine
Вот учебник о том, как его использовать.
Здесь руки в лаборатории.
Ответ 3
Workflow Foundation (.NET 3.0) имеет рабочий процесс конечного автомата. 4.0 не имеет точно такой же вещи в настоящее время, но вы можете определенно создать рабочий процесс конечного автомата с помощью 4.0.
Ответ 4
Я поддерживаю проект с открытым исходным кодом, который реализует (помимо прочего) общий конечный конечный автомат для .NET. Он построен поверх QuickGraph, поэтому вы получаете множество алгоритмов графического анализа бесплатно.
Подробнее о проекте см. на этой странице, а именно " Jolt.Automata: Finite State Machines" для получения дополнительной информации об этой функции.
Ответ 5
Отметьте "Без гражданства" → http://code.google.com/p/stateless/. Его легкая альтернатива тяжелому WWF.
Вот несколько статей автора инструмента:
Государственные машины в моделях доменов
Параметрированные триггеры и возвращающиеся состояния в безстоящем состоянии
Ответ 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
}
}