StepwiseBuilderGenerator 1.0.6

There is a newer version of this package available.
See the version list below for details.
dotnet add package StepwiseBuilderGenerator --version 1.0.6
                    
NuGet\Install-Package StepwiseBuilderGenerator -Version 1.0.6
                    
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="StepwiseBuilderGenerator" Version="1.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StepwiseBuilderGenerator" Version="1.0.6" />
                    
Directory.Packages.props
<PackageReference Include="StepwiseBuilderGenerator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StepwiseBuilderGenerator --version 1.0.6
                    
#r "nuget: StepwiseBuilderGenerator, 1.0.6"
                    
#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.
#addin nuget:?package=StepwiseBuilderGenerator&version=1.0.6
                    
Install as a Cake Addin
#tool nuget:?package=StepwiseBuilderGenerator&version=1.0.6
                    
Install as a Cake Tool

Stepwise Builder Generator

This repository provides a Source Generator that creates strongly-typed, stepwise “fluent” builders for your types. You simply annotate a class with [StepwiseBuilder] and specify the steps you need in the class’s parameterless constructor. The source generator then produces a partial class containing builder interfaces and step methods.

Why Use Stepwise Builders?

  • Compile-time safety: Each required step is enforced in sequence.
  • Reduced boilerplate: No need to handwrite repetitive builder chains.
  • Readable & maintainable: Clean, fluent APIs that guide users step-by-step.

How It Works

  1. Annotate a class with [StepwiseBuilder].
  2. Inside the parameterless constructor, create a chain of methods using GenerateStepwiseBuilder():
    • AddStep<TArgument>(stepName, fieldName = null): adds a step to capture a value of type TArgument.
    • BranchFrom("BaseBuilderName", "BaseBuilderStep") (optional): indicates an alternate path is offered from the step before BaseBuilderStep in BaseBuilderName.
    • CreateBuilderFor<TResult>(): defines the final target type being built.

When you compile, the generator inspects these calls and automatically produces:

  • A partial builder class that implements interfaces representing each step.
  • A chain of interfaces (e.g., IYourClassFirstStep, IYourClassSecondStep, …) to enforce the order of steps.
  • An optional extension method if you used BranchFrom(...), allowing you to jump to a new step at the point * before* a specified step in another builder’s chain.

Quick Start Example

1. Create a Class & Decorate with [StepwiseBuilder]

using StepwiseBuilderGenerator;

[StepwiseBuilder]
public partial class MyClass
{
    public MyClass() // Parameterless constructor
    {
        GenerateStepwiseBuilder()
            .AddStep<int>("FirstStep", "MyIntField")
            .AddStep<string>("SecondStep")  // defaults to "SecondStepValue"
            .AddStep<bool>("ThirdStep")     // further step
            .CreateBuilderFor<MyTargetType>();
    }
}

When you build your project, the generator produces MyClass.g.cs in the same namespace, containing:

  1. IMyClassFirstStep with .FirstStep(int value).
  2. IMyClassSecondStep with .SecondStep(string value).
  3. IMyClassThirdStep with .ThirdStep(bool value).
  4. IMyClassBuild with .Build(Func<MyClass, MyTargetType> buildFunc).
  5. A partial MyClass that implements all the above interfaces, storing step values in fields like public int MyIntField;, public string SecondStepValue;, etc.

2. Using the Generated Builder

var builder = new MyClass();

MyTargetType result = builder
    .FirstStep(42)
    .SecondStep("Hello")
    .ThirdStep(true)
    .Build(instance =>
    {
        return new MyTargetType
        {
            SomeIntProperty = instance.MyIntField,
            SomeStringProperty = instance.SecondStepValue,
            SomeBoolProperty = instance.ThirdStepValue
        };
    });

The stepwise nature ensures you can’t skip or reorder steps; they must be called in the generated sequence.

3. Branching from Another Builder

Suppose we want an alternative path that branches before SecondStep. Here’s our original chain in MyClass:

FirstStep -> SecondStep -> ThirdStep -> Build

By writing:

[StepwiseBuilder]
public partial class MyOtherClass
{
    public MyOtherClass()
    {
        GenerateStepwiseBuilder()
            .BranchFrom("MyClass", "SecondStep")  // offer a path from BEFORE 'SecondStep'
            .AddStep<bool>("AlternateStep")
            .CreateBuilderFor<AnotherType>();
    }
}

We get:

  • A partial MyOtherClass with steps for .AlternateStep(...).
  • An extension method so that right after FirstStep(...) in MyClass, you can choose either to go .SecondStep(...) -> ThirdStep(...) -> Build or .AlternateStep(...) -> Build.
  • Because it’s a separate path, once you choose .AlternateStep(...), you cannot call .ThirdStep(...).

FAQ

1. What if I have generics in my class?

The generator handles generic type parameters by including them in the generated partial class and interfaces.

2. What if I have a branch in a generic class?

If you have a branch (BranchFrom(...)), the branching class should have a matching generic signature (names, constraints, etc.) so the extension methods can properly link the two builders.

3. Can I add custom logic to steps?

Yes. Because the generated class is partial, you can add your own partial methods or fields. Steps themselves are automatically generated as chainable methods.

4. What happens if I omit a step’s fieldName parameter?

The generator will default to naming that field as "{StepName}Value". For example, if your step is .AddStep<int>("Foo"), the field becomes public int FooValue;.

5. Should I always write the build logic in .Build(...)?

Not necessarily. It’s often beneficial to keep the .Build(...) method minimal and place common or advanced build logic in extension methods. For instance, suppose your generated interface is IMyClassBuild; you can do:

public static class MyClassBuilderExtensions
{
    // This extension method extends the build interface directly
    public static MyTargetType BuildMyTarget(this IMyClassBuild builder)
    {
        // Here, we call the underlying Build method, passing in your creation logic.
        // You have direct access via the 'myClass' parameter in the delegate.
        return builder.Build(myClass => 
        {
            return new MyTargetType
            {
                SomeIntProperty    = myClass.MyIntField,
                SomeStringProperty = myClass.SecondStepValue,
                SomeBoolProperty   = myClass.ThirdStepValue
            };
        });
    }
}

Then in user code, you simply do:

var result = new MyClass()
    .FirstStep(42)
    .SecondStep("Hello")
    .ThirdStep(true)
    .BuildMyTarget();

This keeps your builder usage consistent while consolidating object-creation details elsewhere.


Steps Enum

Each generated builder class includes enum Steps listing all steps (excluding the final Build) in the order they were declared. You might use this for logging, debugging, or reflection-based logic if desired.


Factory Methods in StepwiseBuilders

For each generated base builder, the generator also provides a static factory method within the StepwiseBuilders partial class. These methods allow you to conveniently initialize a builder without directly instantiating the generated partial class.


Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
4.0.0 130 6/16/2025
3.0.0 234 5/14/2025
2.2.2 175 4/28/2025
2.2.1 93 4/26/2025
2.2.0 85 4/26/2025
2.1.3 101 4/25/2025
2.1.2 98 4/25/2025
2.1.1 111 4/25/2025
2.1.0 156 4/24/2025
2.0.2 154 4/24/2025
2.0.1 154 4/24/2025
2.0.0 164 4/23/2025
1.0.6 481 3/25/2025
1.0.5 475 3/25/2025
1.0.4 461 3/24/2025
1.0.3 107 1/13/2025
1.0.2 87 1/13/2025
1.0.1 100 1/9/2025
1.0.0 101 1/9/2025