LightChain 0.1.0

dotnet add package LightChain --version 0.1.0                
NuGet\Install-Package LightChain -Version 0.1.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LightChain" Version="0.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LightChain --version 0.1.0                
#r "nuget: LightChain, 0.1.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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 86 5/27/2024

0.1.0
- Initial release.