Skip to content

Instantly share code, notes, and snippets.

@seclerp
Created September 14, 2020 16:16
Show Gist options
  • Save seclerp/1162e741ab2f374b370bc1bc9e8d1ef1 to your computer and use it in GitHub Desktop.
Save seclerp/1162e741ab2f374b370bc1bc9e8d1ef1 to your computer and use it in GitHub Desktop.
[C#] Chain of Responsibility pattern wthout reflection
public class Context
{
public int Counter { get; set; }
}
public class FirstStep : IPipelineStep<Context>
{
private readonly IPipelineStep<Context> _next;
public FirstStep(IPipelineStep<Context> next)
{
_next = next;
}
public Task Execute(Context context)
{
Console.WriteLine($"Hello {context.Counter}");
context.Counter++;
return _next?.Execute(context);
}
}
public interface IPipelineBuilder<TContext>
{
IPipelineBuilder<TContext> SetNext(Func<IPipelineStep<TContext>, IPipelineStep<TContext>> nestStepFactory);
IPipelineStep<TContext> Build();
}
public interface IPipelineStep<TContext>
{
Task Execute(TContext context);
}
public class PipelineBuilder<TContext> : IPipelineBuilder<TContext>
{
private Stack<Func<IPipelineStep<TContext>, IPipelineStep<TContext>>> _stepsFactories;
public PipelineBuilder()
{
_stepsFactories = new Stack<Func<IPipelineStep<TContext>, IPipelineStep<TContext>>>();
}
public IPipelineBuilder<TContext> SetNext(Func<IPipelineStep<TContext>, IPipelineStep<TContext>> nestStepFactory)
{
_stepsFactories.Push(nestStepFactory);
return this;
}
public IPipelineStep<TContext> Build()
{
if (!_stepsFactories.TryPop(out var currentFactory))
{
return null;
}
// Null because this is actually the last step without any others after him
var currentStep = currentFactory(null);
while (_stepsFactories.TryPop(out var stepFactory))
{
currentStep = stepFactory(currentStep);
}
return currentStep;
}
}
class Program
{
static async Task Main(string[] args)
{
var pipeline =
new PipelineBuilder<Context>()
.SetNext(next => new FirstStep(next))
.SetNext(next => new SecondStep(next))
.SetNext(next => new ThirdStep(next))
.Build();
var context = new Context { Counter = 1 };
await pipeline.Execute(context);
}
}
public class SecondStep : IPipelineStep<Context>
{
private readonly IPipelineStep<Context> _next;
public SecondStep(IPipelineStep<Context> next)
{
_next = next;
}
public Task Execute(Context context)
{
Console.WriteLine($"World {context.Counter}");
context.Counter++;
return _next?.Execute(context);
}
}
public class ThirdStep : IPipelineStep<Context>
{
private readonly IPipelineStep<Context> _next;
public ThirdStep(IPipelineStep<Context> next)
{
_next = next;
}
public Task Execute(Context context)
{
Console.WriteLine("Hello World");
return Task.CompletedTask;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment