Akka.NET actor has really useful feature is switching the behavior using Become() method. It inspired me to make simple implementation to use Become() separately outside Akka.NET.
StateMachine can be used via Inheritance (IS-A) see StateMachineBase or Composition (HAS-A) see example below. StateMachine supports sync and async handlers.
See example of usage here:
publicclassDelivery{privatereadonlyIStateMachineit=newStateMachine();publicstringStateName;publicDelivery(){it.Become(New);}publicvoidHandle<TMessage>(TMessagemsg)=>it.Handle(msg);privatevoidNew(){StateName=nameof(New);it.Receive<Send>(msg =>{// sent logicit.Become(Sent);});it.Receive<Cancel>(msg =>{// cancel logicit.Become(Canceled);});it.ReceiveAny(NotSupported);}privatevoidSent(){StateName=nameof(Sent);it.Receive<Receive>(msg =>{// receive logicit.Become(Received);});it.ReceiveAny(NotSupported);}privatevoidCanceled(){StateName=nameof(Canceled);it.ReceiveAny(NotSupported);}privatevoidReceived(){StateName=nameof(Received);it.ReceiveAny(NotSupported);}privateobjectNotSupported(objectmsg){thrownewNotSupportedException();}publicclassSend{publicstringAddress;}publicclassReceive{publicstringFeedback;}publicclassCancel{publicstringReason;}}classDeliveryExamples{voidItCanSendThenReceive(){vardelivery=newDelivery();delivery.Handle(newDelivery.Send{Address="Redmond, WA 98052-7329, USA"});delivery.Handle(newDelivery.Receive{Feedback="Wow, thanks!"});}voidItCanCancel(){vardelivery=newDelivery();delivery.Handle(newDelivery.Cancel{Reason="Running out of money"});delivery.Handle(newDelivery.Send{Address="Redmond, WA 98052-7329, USA"});// NotSupportedException}voidItCanNotCancel(){vardelivery=newDelivery();delivery.Handle(newDelivery.Send{Address="Redmond, WA 98052-7329, USA"});delivery.Handle(newDelivery.Cancel{Reason="Running out of money"});// NotSupportedException}}