| name | IncrementalSourceGenerator.BuilderPattern |
| nuget | https://www.nuget.org/packages/IncrementalSourceGenerator.BuilderPattern/ |
| link | https://github.com/MartinBarrettNielsen11/Incremental-source-generator-builder-pattern |
| author | Martin Barrett Nielsen |
Generate builder pattern code for classes with many properties
This is how you can use IncrementalSourceGenerator.BuilderPattern .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IncrementalSourceGenerator.BuilderPattern" Version="1.0.2" />
</ItemGroup>
</Project>
The code that you will use is
using Builder;
Console.WriteLine("create person builder");
var p = new PersonBuilder()
.WithFirstName("Andrei")
.WithLastName("Ignat")
.Build();
Console.WriteLine(p.FullName());
using Generator;
namespace Builder;
[Builder(typeof(Person))]
public partial class PersonBuilder
{
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName() => $"{FirstName} {LastName}";
}
The code that is generated is
#nullable enable
#pragma warning disable CA1813, CA1019, IDE0065, IDE0034, IDE0055
using System;
namespace Generator;
[System.CodeDom.Compiler.GeneratedCode("Generator", "v1")]
[AttributeUsage(AttributeTargets.Class)]
public sealed class BuilderAttribute(Type type) : Attribute
{
public Type TargetType { get; } = type;
}
#pragma warning restore CA1813, CA1019, IDE0065, IDE0034, IDE0055
#nullable enable
#pragma warning disable IDE0055, IDE0008
using System;
using System.Linq;
using System.Collections.Generic;
using Generator;
namespace Builder;
[System.CodeDom.Compiler.GeneratedCode("Generator", "v1")]
public partial class Person
{
private Func<Builder.PersonBuilder> _factory = () => new();
private readonly List<Action<Builder.PersonBuilder>> _domainRules = new();
/// <summary>
/// Returns configured instance of Builder.PersonBuilder
/// </summary>
public Builder.PersonBuilder Build()
{
Builder.PersonBuilder instance = _factory();
_domainRules.ForEach(action => action(instance));
return instance;
}
}
#pragma warning restore IDE0055, IDE0008
#nullable enable
#pragma warning disable IDE0055, IDE0008
using System;
using System.Linq;
using System.Collections.Generic;
using Generator;
namespace Builder;
[System.CodeDom.Compiler.GeneratedCode("Generator", "v1")]
public partial class PersonBuilder
{
private Func<Builder.Person> _factory = () => new();
private readonly List<Action<Builder.Person>> _domainRules = new();
private Func<string>? _firstName;
private Func<string>? _lastName;
public PersonBuilder WithFirstName(string @firstName)
{
return WithFirstName(() => @firstName);
}
public PersonBuilder WithFirstName(Func<string> @firstName)
{
_firstName = @firstName;
return this;
}
public PersonBuilder WithLastName(string @lastName)
{
return WithLastName(() => @lastName);
}
public PersonBuilder WithLastName(Func<string> @lastName)
{
_lastName = @lastName;
return this;
}
/// <summary>
/// Returns configured instance of Builder.Person
/// </summary>
public Builder.Person Build()
{
Builder.Person instance = _factory();
if(_firstName is not null)
instance.FirstName = _firstName.Invoke();
if(_lastName is not null)
instance.LastName = _lastName.Invoke();
_domainRules.ForEach(action => action(instance));
return instance;
}
}
#pragma warning restore IDE0055, IDE0008
#pragma warning disable IDE0055, IDE0008
#nullable enable
using System;
using System.Collections.Generic;
namespace Generator;
[System.CodeDom.Compiler.GeneratedCode("Generator", "v1")]
public static class DomainAssertionExtensions
{
/// <summary>
/// Adds a domain validation rule to be executed during the build phase.
/// </summary>
/// <param name="_domainRules">The list of post-build domain rules.</param>
/// <param name="predicate">A function that returns true when the entity violates a rule.</param>
/// <param name="errorMessage">The error message that will be thrown if the rule fails.</param>
public static void AddDomainRule<TEntity>(
this List<Action<TEntity>> _domainRules,
Func<TEntity, bool> predicate,
string errorMessage)
{
_domainRules.Add(e =>
{
if (predicate(e))
throw new InvalidOperationException(errorMessage);
});
}
}
#pragma warning restore IDE0055, IDE0008
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/IncrementalSourceGenerator.BuilderPattern