Skip to content

Instantly share code, notes, and snippets.

@nordfjord
Created June 28, 2021 19:51
Show Gist options
  • Save nordfjord/e4bb4ceb325f1459ee44e13b1348da58 to your computer and use it in GitHub Desktop.
Save nordfjord/e4bb4ceb325f1459ee44e13b1348da58 to your computer and use it in GitHub Desktop.
Processor in c#
using System;
using System.Collections.Generic;
using System.Linq;
namespace ProcessorDemo
{
public interface IProcessor<Event, Command, State>
{
public State InitialState { get; }
public State Evolve(State state, Event @event);
public IEnumerable<Command> React(State state, Event @event);
}
public enum PaymentStatus
{
None, InProgress, Succeeded, Failed
}
public interface PaymentEvent
{
}
public class PaymentRequested: PaymentEvent {
public string Id { get; set; }
}
public class PaymentFailed: PaymentEvent {
public string Id { get; set; }
}
public class PaymentSucceeded: PaymentEvent {
public string Id { get; set; }
}
public interface PaymentCommand
{
}
public class Pay : PaymentCommand
{
public string Id { get; set; }
}
public class ProcessPayment : PaymentCommand
{
public string Id { get; set; }
}
public class PaymentProcessor : IProcessor<PaymentEvent, PaymentCommand, PaymentStatus>
{
public PaymentStatus InitialState { get; } = PaymentStatus.None;
public PaymentStatus Evolve(PaymentStatus state, PaymentEvent @event)
{
return @event switch
{
PaymentRequested => PaymentStatus.InProgress,
PaymentSucceeded => PaymentStatus.Succeeded,
PaymentFailed => PaymentStatus.Failed,
_ => state
};
}
public IEnumerable<PaymentCommand> React(PaymentStatus state, PaymentEvent @event)
{
if (state != PaymentStatus.None) return Enumerable.Empty<PaymentCommand>();
return @event switch
{
PaymentRequested e => new[] {new ProcessPayment {Id = e.Id}},
_ => Enumerable.Empty<PaymentCommand>()
};
}
}
public class ListProcessor<Event, Command, State> : IProcessor<Event, Command, Dictionary<string, State>>
{
private readonly IProcessor<Event, Command, State> _processor;
private readonly Func<Event, string> _getId;
public ListProcessor(IProcessor<Event, Command, State> processor, Func<Event, string> getId)
{
_processor = processor;
_getId = getId;
}
public Dictionary<string, State> InitialState { get; } = new();
public Dictionary<string, State> Evolve(Dictionary<string, State> state, Event @event)
{
var id = _getId(@event);
var innerState = state[id] ?? _processor.InitialState;
var newState = _processor.Evolve(innerState, @event);
state[id] = newState;
return state;
}
public IEnumerable<Command> React(Dictionary<string, State> state, Event @event)
{
return _processor.React(state[_getId(@event)] ?? _processor.InitialState, @event);
}
}
}
namespace ProcessorDemo {
public class Program {
public static void Main(string[] args)
{
var processor = new ListProcessor<PaymentEvent, PaymentCommand, PaymentStatus>(new PaymentProcessor(), @event => @event switch
{
PaymentRequested e => e.Id,
PaymentSucceeded e => e.Id,
PaymentFailed e => e.Id,
_ => throw new ArgumentOutOfRangeException(nameof(@event), @event, null)
});
processor.React(processor.InitialState, new PaymentRequested {Id = "1"});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment