Knara.SourceGenerators.DesignPatterns.Builder 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Knara.SourceGenerators.DesignPatterns.Builder --version 1.0.0
                    
NuGet\Install-Package Knara.SourceGenerators.DesignPatterns.Builder -Version 1.0.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="Knara.SourceGenerators.DesignPatterns.Builder" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Knara.SourceGenerators.DesignPatterns.Builder" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Knara.SourceGenerators.DesignPatterns.Builder" />
                    
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 Knara.SourceGenerators.DesignPatterns.Builder --version 1.0.0
                    
#r "nuget: Knara.SourceGenerators.DesignPatterns.Builder, 1.0.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.
#:package Knara.SourceGenerators.DesignPatterns.Builder@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Knara.SourceGenerators.DesignPatterns.Builder&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Knara.SourceGenerators.DesignPatterns.Builder&version=1.0.0
                    
Install as a Cake Tool

Builder Pattern Generator

A C# source generator that creates fluent builder classes for complex object construction in .NET Framework applications. Automatically generates type-safe builders with validation, required field checking, and collection handling.

Why This Generator Exists

Legacy Framework Reality: .NET Framework 4.x lacks modern language features like init properties, nullable reference types, and advanced object initializers. Creating immutable, validated objects requires verbose constructors or error-prone manual builder implementations.

Team Skill Constraints: Implementing correct builder patterns manually requires understanding of fluent interfaces, validation chains, and immutability patterns that inexperienced developers often get wrong.

Solution: Generate proven, consistent builder implementations that provide modern object construction patterns for legacy frameworks.

Quick Start

Add the source generator to your project:

<ItemGroup> <ProjectReference Include="path/to/Knara.SourceGenerators.DesignPatterns.Builder.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>

Or via NuGet (when published):

dotnet add package Knara.SourceGenerators.DesignPatterns.Builder

If you are using the generator in .net 4.+ projects, refer to this guide for additional steps.

using Knara.SourceGenerators.DesignPatterns.Builder;

[GenerateBuilder]
public class User
{
    [BuilderProperty(Required = true)]
    public string FirstName { get; }
    
    [BuilderProperty]
    public string LastName { get; }
    
    [BuilderProperty(ValidatorMethod = nameof(ValidateAge))]
    public int Age { get; }
    
    public User(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName; 
        Age = age;
    }
    
    public static bool ValidateAge(int age) => age >= 0 && age <= 150;
}

// Usage
var user = UserBuilder.Create()
    .WithFirstName("John")
    .WithLastName("Doe") 
    .WithAge(30)
    .Build();

Builder Configuration

Class-Level Attributes

[GenerateBuilder(
    BuilderName = "CustomBuilder",           // Override default name
    ValidateOnBuild = true,                  // Check required fields
    GenerateWithMethods = true,              // Generate WithXxx methods  
    GenerateFromMethod = true,               // Generate From() method
    Accessibility = BuilderAccessibility.Internal  // Control visibility
)]

Property-Level Attributes

[BuilderProperty(
    Required = true,                         // Must be set before Build()
    ValidatorMethod = "ValidateEmail",       // Custom validation method
    DefaultValue = "\"Unknown\"",            // Default value
    CustomSetterName = "WithEmailAddress",  // Override method name
    AllowNull = false,                       // Null checking
    IgnoreInBuilder = true                   // Exclude from builder
)]

Collection Attributes

[BuilderCollection(
    AddMethodName = "AddTag",                // Single item method name
    AddRangeMethodName = "AddTags",          // Range method name  
    GenerateClearMethod = true,              // Generate Clear method
    GenerateCountProperty = true             // Generate Count property
)]

Use Cases by Complexity

1. Simple Configuration Objects

When: Objects with optional parameters and defaults

[GenerateBuilder]
public class DatabaseConfig
{
    [BuilderProperty(Required = true)]
    public string ConnectionString { get; }
    
    [BuilderProperty]
    public TimeSpan Timeout { get; } = TimeSpan.FromSeconds(30);
    
    [BuilderProperty] 
    public int MaxRetries { get; } = 3;
}

2. Domain Entities with Validation

When: Business objects needing validation before construction

[GenerateBuilder(ValidateOnBuild = true)]
public class Customer
{
    [BuilderProperty(Required = true, ValidatorMethod = nameof(ValidateEmail))]
    public string Email { get; }
    
    [BuilderProperty(Required = true)]
    public string Name { get; }
    
    [BuilderProperty(ValidatorMethod = nameof(ValidateAge))]
    public int Age { get; }
    
    public static bool ValidateEmail(string email) => email.Contains("@");
    public static bool ValidateAge(int age) => age >= 18;
}

3. Complex Objects with Collections

When: Objects with multiple collections and complex structure

[GenerateBuilder]
public class ProjectConfiguration
{
    [BuilderProperty(Required = true)]
    public string Name { get; }
    
    [BuilderCollection(AddMethodName = "AddDependency")]
    public IReadOnlyList<string> Dependencies { get; }
    
    [BuilderCollection]
    public List<string> Tags { get; }
    
    [BuilderProperty]
    public Dictionary<string, string> Metadata { get; }
}

4. API Configuration Objects

When: Service configurations with many optional parameters

[GenerateBuilder]
public class ApiClientConfig
{
    [BuilderProperty(Required = true)]
    public string BaseUrl { get; }
    
    [BuilderProperty]
    public TimeSpan Timeout { get; } = TimeSpan.FromSeconds(30);
    
    [BuilderProperty]
    public AuthenticationType AuthType { get; } = AuthenticationType.None;
    
    [BuilderCollection]
    public IReadOnlyList<string> DefaultHeaders { get; }
}

Generated Features

Core Builder Methods

  • Create() - Static factory method
  • WithXxx() - Fluent setters for each property
  • Build() - Creates the final object
  • From(existing) - Initialize from existing object
  • ToBuilder() - Extension method for existing objects

Collection Support

  • AddXxx() - Add single items
  • AddXxxs() - Add multiple items
  • ClearXxx() - Clear collections
  • XxxCount - Get collection counts

Validation Features

  • Required field checking
  • Custom validation methods
  • Null value validation
  • Build-time validation with clear error messages

Legacy Framework Benefits

✅ Solves Legacy Problems

  • Immutable objects without init properties
  • Validation without nullable reference types
  • Fluent APIs without manual implementation
  • Required fields without compiler support
  • Collection building with type safety

✅ Team Safety Features

  • Generated validation prevents runtime errors
  • Consistent patterns across codebase
  • Clear error messages for missing required fields
  • Type-safe builders eliminate casting errors

Performance Considerations

Memory Usage

  • Additional allocations: Builder instances and intermediate collections
  • Garbage collection: More objects to collect during build process

Build Performance

  • Compile-time generation: No runtime reflection overhead
  • Direct method calls: Faster than dynamic construction
  • Validation overhead: Custom validators run at build time

Best Practices

✅ Good Uses

  • Configuration objects with many optional parameters
  • Domain entities requiring validation
  • API builders for complex integrations
  • Data transfer objects needing immutability
  • Test data builders for unit tests

❌ Avoid For

  • Simple DTOs with 2-3 properties
  • Performance-critical paths with high allocation rates
  • Value objects better suited for constructors
  • Objects changing frequently (maintenance overhead)

Design Guidelines

  • Keep builders focused: One builder per aggregate root
  • Use validation sparingly: Only for business rules, not basic null checks
  • Prefer init over set: Use { get; } properties when possible
  • Group related properties: Use nested builders for complex hierarchies

Validation Patterns

Custom Validators

public static bool ValidateEmail(string email)
{
    return !string.IsNullOrEmpty(email) && email.Contains("@");
}

public static bool ValidateAge(int age)
{
    return age >= 0 && age <= 150;
}

Required Field Strategy

// Runtime validation
[BuilderProperty(Required = true)]
public string Name { get; }

// Usage - throws InvalidOperationException if Name not set
var obj = builder.Build(); 

Null Handling

// Strict null checking
[BuilderProperty(AllowNull = false)]
public string Name { get; }

// Nullable fields  
[BuilderProperty(AllowNull = true)]
public string? Description { get; }

Migration Strategy

From Constructor Overloads

Before:

public DatabaseConfig(string connectionString)
    : this(connectionString, TimeSpan.FromSeconds(30), 100) { }

public DatabaseConfig(string connectionString, TimeSpan timeout)  
    : this(connectionString, timeout, 100) { }

public DatabaseConfig(string connectionString, TimeSpan timeout, int poolSize)
{
    // Implementation
}

After:

[GenerateBuilder]
public class DatabaseConfig
{
    [BuilderProperty(Required = true)]
    public string ConnectionString { get; }
    // Builder handles all combinations
}

From Mutable Objects

Before:

var config = new DatabaseConfig();
config.ConnectionString = "...";  // Mutable, error-prone
config.Timeout = TimeSpan.FromSeconds(30);

After:

var config = DatabaseConfigBuilder.Create()
    .WithConnectionString("...")
    .WithTimeout(TimeSpan.FromSeconds(30))
    .Build();  // Immutable result

Integration with Legacy Code

Gradual Adoption

  1. Start with new classes: Apply [GenerateBuilder] to new domain objects
  2. Migrate complex constructors: Replace parameter-heavy constructors
  3. Convert test builders: Replace manual test data builders
  4. Standardize configurations: Use for service configuration objects

Coexistence Patterns

// Support both patterns during transition
public class LegacyClass
{
    // Keep existing constructors
    public LegacyClass(string name) { Name = name; }
    
    // Add builder support
    [BuilderProperty] 
    public string Name { get; }
}

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
1.1.0 194 10/25/2025
1.0.3 191 9/26/2025
1.0.2 234 9/24/2025
1.0.1 232 9/24/2025
1.0.0 225 9/23/2025