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