LightChain 0.1.0
dotnet add package LightChain --version 0.1.0
NuGet\Install-Package LightChain -Version 0.1.0
<PackageReference Include="LightChain" Version="0.1.0" />
paket add LightChain --version 0.1.0
#r "nuget: LightChain, 0.1.0"
// Install LightChain as a Cake Addin #addin nuget:?package=LightChain&version=0.1.0 // Install LightChain as a Cake Tool #tool nuget:?package=LightChain&version=0.1.0
Light Chain
Lightweight library for implementing simplified version of chain of responsibility in C#.
The inspiration for this library came from figuring out a way to break up if/else
chains into loosely coupled, separate units to improve maintainability through separation of concerns.
Example of if/else
chain:
public class Main
{
public string Run()
{
var result = ProcessAnimal("dog", "red", 100);
return result;
}
private string ProcessAnimal(string animal, string color, int height)
{
string result;
if (animal == "cat") {
result = "animal is a cat!";
} else if (color == "red" {
result = "animal is red!";
} else {
result = "it is an animal";
}
return result;
}
}
As we can see from the example, all the blocks of conditions and processing are stuck together in the if/else
construct within the same class. The if/else
construct itself adds a bit of noise. It is difficult to view and change high level concerns only, such as order of each case.
Getting Started
Installation
Add the library via NuGet to the project(s) that you want to use Light Chain:
- Either via Project > Manage NuGet Packages... / Browse / search for light-chain / Install
- Or by running a command in the Package Manager Console
Install-Package LightChain
Usage
Create a type to hold the input:
public class AnimalProcessorInput
{
public required string Animal { get; set; }
public required string Color { get; set; }
public required int Height { get; set; }
}
Derive a processor interface from IProcessor
:
using LightChain;
public interface IAnimalProcessor : IProcessor<AnimalProcessorInput, string>
{
}
Create each of the processors derived from the interface you just created:
public class CatsOnlyProcessor : IAnimalProcessor
{
public bool Condition(AnimalProcessorInput input) => input.Animal == "cat";
public string Process(AnimalProcessorInput input)
{
return "animal is a cat!";
}
}
public class RedOnlyProcessor : IAnimalProcessor
{
public bool Condition(AnimalProcessorInput input) => input.Color == "red";
public string Process(AnimalProcessorInput input)
{
return "animal is red!";
}
}
public class DefaultProcessor : IAnimalProcessor
{
public bool Condition(AnimalProcessorInput input) => true;
public string Process(AnimalProcessorInput input)
{
return "it is an animal";
}
}
Now you can create the chain and use it with the input:
using LightChain;
public class Main
{
public string Run()
{
var result = ProcessAnimal("dog", "red", 100);
return result;
}
private string ProcessAnimal(string animal, string color, int height)
{
var processors = new List<IAnimalProcessor>
{
new CatsOnlyProcessor(),
new RedOnlyProcessor(),
new DefaultProcessor(),
};
var animalProcessor = new Chain<IAnimalProcessor, AnimalProcessorInput, string>(processors);
var input = new AnimalProcessorInput
{
Animal = "dog",
Color = "red",
Height = 100,
};
var result = animalProcessor.Run(input);
return result;
}
}
Be aware that the order of the processors in the list matters: the first processor whose condition returns true
will handle returning the output.
Dependency Injection
Using a dependency injection framework, the processor list and chain instance can be defined separately from the main class via the dependency injection framework.
Using Microsoft.Extensions.DependencyInjection the Main
class can be refactored:
using LightChain;
public class Main
{
private readonly IChain<AnimalProcessorInput, string> animalProcessor;
public Main(IChain<AnimalProcessorInput, string> animalProcessor)
{
this.animalProcessor = animalProcessor;
}
public string Run()
{
var input = new AnimalProcessorInput
{
Animal = "dog",
Color = "red",
Height = 100,
};
var result = animalProcessor.Run(input);
return result;
}
}
The main, processors, and chain classes can be registered with the DI framework:
using Microsoft.Extensions.DependencyInjection;
using LightChain;
internal static class ServiceRegistrations
{
public static void AddServices(this IServiceCollection services)
{
// processor registration order matters
services.AddTransient<IAnimalProcessor, CatsOnlyProcessor>();
services.AddTransient<IAnimalProcessor, RedOnlyProcessor>();
services.AddTransient<IAnimalProcessor, DefaultProcessor>();
services.AddTransient<IChain<AnimalProcessorInput, string>, Chain<IAnimalProcessor, AnimalProcessorInput, string>>();
services.AddTransient<Main>();
}
}
The end result is improved separation of concerns such that the main class no longer needs to change due to any modifications related to processors:
- Adding or removing processors from the chain.
- Reordering processors in the chain.
- Changing implementation details of a processor.
Also, each processor is completely separate from each other and the chain.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.0 | 111 | 5/27/2024 |
0.1.0
- Initial release.