A Custom Property Builder in .NET typically refers to implementing the Fluent Builder Pattern, a creational design pattern used to construct complex objects step-by-step using method chaining. This pattern is highly prevalent in modern .NET systems—seen in frameworks like HostApplicationBuilder and Entity Framework Core’s PropertyBuilder—because it eliminates messy constructors, guarantees object validity, and supports immutability. Key Components of a Fluent Property Builder
The Target Product: The complex domain class or data transfer object (DTO) being built. Its constructor or properties are usually kept internal or private to prevent direct instantiation.
Fluent Methods (With…): Methods within the builder that configure specific properties and return this (the builder instance) to enable method chaining.
The Build() Method: The final step that validates the aggregated properties, instantiates the target object, and returns it. Step-by-Step Code Example
The following example demonstrates how to build a custom property builder for an immutable User profile entity. 1. Define the Immutable Target Class
public class User { public string Id { get; } public string FirstName { get; } public string LastName { get; } public string Email { get; } public int Age { get; } // Enforce object creation through the builder by making the constructor internal internal User(string id, string firstName, string lastName, string email, int age) { FirstName = firstName; LastName = lastName; Email = email; Age = age; } } Use code with caution. 2. Implement the Custom Property Builder
public class UserBuilder { // Default values for properties private string _id = Guid.NewGuid().ToString(); private string _firstName = string.Empty; private string _lastName = string.Empty; private string _email = string.Empty; private int _age; // Fluent method for configuring FirstName public UserBuilder WithFirstName(string firstName) { _firstName = firstName; return this; // Returns the builder instance for chaining } // Fluent method for configuring LastName public UserBuilder WithLastName(string lastName) { _lastName = lastName; return this; } // Fluent method for configuring Email public UserBuilder WithEmail(string email) { _email = email; return this; } // Fluent method for configuring Age public UserBuilder WithAge(int age) { _age = age; return this; } // The validation and object assembly step public User Build() { // Enforce business rules before creation if (string.IsNullOrWhiteSpace(_firstName) || string.IsNullOrWhiteSpace(_lastName)) { throw new InvalidOperationException(“User must have a first and last name.”); } if (!_email.Contains(“@”)) { throw new ArgumentException(“A valid email address is required.”); } return new User(_id, _firstName, _lastName, _email, _age); } } Use code with caution. 3. Consume the Property Builder
// Fluent initialization using method chaining User newUser = new UserBuilder() .WithFirstName(“Jane”) .WithLastName(“Doe”) .WithEmail(“[email protected]”) .WithAge(30) .Build(); Use code with caution. Advanced Scenarios & Extensibility
Interface Segregation for Strict Sequencing: If properties must be initialized in a strict order (e.g., you cannot set Email without setting Name first), split the builder into multiple interfaces (e.g., INameStage, IEmailStage, IBuildStage) and have the builder methods return the next stage interface instead of this.
Entity Framework Core Customizations: If your goal is instead to write custom data mapping configurations for EF Core, you can extend EF Core’s modeling pipeline by implementing custom database conventions or creating extension methods targeting the built-in PropertyBuilder class.
If you are tailoring this for a specific system, please let me know:
Will this builder be used for domain models, unit testing data, or framework configuration?
Do you need to enforce a strict chronological sequence for setting properties?
Should the target object be completely immutable after creation?
Implement a custom configuration provider – .NET – Microsoft Learn
Leave a Reply