Skip to content

ndcorder/BuilderGen

Repository files navigation

BuilderGen

A Roslyn source generator that creates fluent Builder classes for your records and immutable types.

No runtime dependencies. Fully AOT-compatible. Zero reflection.

Installation

dotnet add package BuilderGen

Quick Start

Mark any record, class, or struct with [GenerateBuilder]:

using BuilderGen;

[GenerateBuilder]
public record Order(string CustomerId, List<LineItem> Items, decimal Discount = 0);

[GenerateBuilder]
public record LineItem(string Sku, int Quantity);

A fluent builder is generated automatically:

var order = new OrderBuilder()
    .WithCustomerId("C123")
    .AddItem(new LineItem("SKU1", 2))
    .WithDiscount(0.1m)
    .Build();

Features

Fluent With* Methods

Every constructor parameter gets a With{Name}() method that returns the builder for chaining.

var person = new PersonBuilder()
    .WithFirstName("Alice")
    .WithLastName("Smith")
    .WithAge(30)
    .Build();

Required Property Tracking

Properties without default values are required. Build() throws InvalidOperationException with a clear message if any required property is missing:

var builder = new PersonBuilder()
    .WithFirstName("Alice");
    // LastName not set!

builder.Build(); // throws: "The following required properties were not set: LastName"

Optional Properties

Parameters with default values are optional — you can omit them:

[GenerateBuilder]
public record Order(string CustomerId, decimal Discount = 0);

var order = new OrderBuilder()
    .WithCustomerId("C123")
    .Build(); // Discount defaults to 0

Collection Initializers

For List<T>, IList<T>, IEnumerable<T>, ICollection<T>, IReadOnlyList<T>, and IReadOnlyCollection<T> properties, both With{Name}() and Add{SingularName}() methods are generated:

var cart = new ShoppingCartBuilder()
    .WithOwner("Alice")
    .AddItem("Apple")
    .AddItem("Banana")
    .Build();

Nested Builders

If a property's type also has [GenerateBuilder], a Configure{Name}() method is generated:

[GenerateBuilder]
public record Address(string Street, string City);

[GenerateBuilder]
public record Person(string Name, Address HomeAddress);

var person = new PersonBuilder()
    .WithName("Alice")
    .ConfigureHomeAddress(a => a
        .WithStreet("123 Main St")
        .WithCity("Springfield"))
    .Build();

Supported Types

  • Records (record, record struct)
  • Classes (with explicit constructors)
  • Structs (with explicit constructors)

How It Works

BuilderGen is a Roslyn incremental source generator. At compile time it:

  1. Finds types marked with [GenerateBuilder]
  2. Extracts constructor parameters via the semantic model
  3. Emits a {TypeName}Builder class in the same namespace

No runtime code is shipped — the generator runs only during compilation.

API Reference

Attribute Target Effect
[GenerateBuilder] class, record, struct Generates a {TypeName}Builder class

Generated Builder Members

Member Description
With{Property}(T value) Sets the property value, returns builder
Add{Singular}(T item) Adds to collection property, returns builder
Configure{Property}(Action<TBuilder>) Configures nested builder type, returns builder
Build() Creates the target instance, validates required properties

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new functionality
  4. Run dotnet test to verify
  5. Submit a pull request

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages