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