CodingFlow / decorator-generator

Source generator for decorator pattern boilerplate code in C#.
Apache License 2.0
11 stars 5 forks source link
csharp csharp-sourcegenerator roslyn source-generator source-generators

Decorator Generator

Nuget GitHub Workflow Status (with event) Nuget GitHub Sponsors

Source generator for decorator pattern boilerplate code in C#.

When implementing the decorator pattern in C#, it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for.

decorator-pattern-uml

Getting Started

Installation

Add the library via NuGet to the project(s) that you want to auto-generate abstract decorator classes for:

Install-Package DecoratorGenerator

Usage

Add a Decorate attribute to the interface:

using DecoratorGenerator;

namespace SampleLibrary;

[Decorate]
public interface ICat
{
    string Meow();
}

Build the project so the abstract class is generated for the interface. The generated class will be named after the interface, but without the I prefix. In this case, since the interface is ICat the class will be CatDecorator. Then create your decorator class as usual:

namespace SampleLibrary;

public class BarkingCat : CatDecorator
{
    public BarkingCat(ICat cat) : base(cat)
    {

    }

    public override string Meow()
    {
        return $"woof woof - {base.Meow()}";
    }
}

Example usage of the decorator:

using SampleLibrary;

namespace SampleApp;

partial class Program
{

    static void Main(string[] args)
    {
        var cat = new BarkingCat(new Cat());
        var sound = cat.Meow();

        Console.WriteLine(sound);
    }

}

Configuration

List of Target Interfaces in a Config file

To generate decorator abstract classes for third party interfaces, Decorator Generator will look for a struct named WrapperList and generate classes of the types in the fields of the WrapperList:

using Amazon.DynamoDBv2.DataModel;

public struct WrapperList
{
    // name the field whatever you want, the name isn't used, only the type is used.
    IDynamoDBContext dynamoDBContext;
}

In this case, it will generate a class for IDynamoDBContext called DynamoDBContextDecorator. This feature will also work for your own interfaces if you prefer this approach instead of using the attribute.