Skip to content

Instantly share code, notes, and snippets.

@schwastek
Last active January 6, 2024 14:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schwastek/6a2c6e846823ebd4cf2fd7af21758d46 to your computer and use it in GitHub Desktop.
Save schwastek/6a2c6e846823ebd4cf2fd7af21758d46 to your computer and use it in GitHub Desktop.
using System;
namespace BuilderWithImplicitConversion;
// Usage
public class Program
{
static void Main(string[] args)
{
// Builder pattern usage with `Build()` method call omitted thanks to implicit operator
User user = new UserBuilder()
.WithFirstName("John")
.WithLastName("Doe")
.WithAge(25)
.WithAuthentication(
new AuthenticationBuilder()
.WithUsername("jdoe")
.WithPassword("password123")
);
Console.WriteLine($"User: {user.FirstName}, {user.LastName}, {user.Age}");
Console.WriteLine($"Authentication: {user.Authentication?.Username}, {user.Authentication?.Password}");
// Real-world example usage when setting up data for test fixture
user = TestHelper.BuildUserWithAuthentication(userBuilder => userBuilder.WithFirstName("Jane"));
Console.WriteLine($"User: {user.FirstName}, {user.LastName}, {user.Age}");
}
}
// Builders
public class UserBuilder : BaseBuilder<User>
{
protected override User Instance { get; } = new();
public UserBuilder WithFirstName(string firstName)
{
Instance.FirstName = firstName;
return this;
}
public UserBuilder WithLastName(string lastName)
{
Instance.LastName = lastName;
return this;
}
public UserBuilder WithAge(int age)
{
Instance.Age = age;
return this;
}
public UserBuilder WithAuthentication(Authentication authentication)
{
Instance.Authentication = authentication;
return this;
}
}
public class AuthenticationBuilder : BaseBuilder<Authentication>
{
protected override Authentication Instance { get; } = new();
public AuthenticationBuilder WithUsername(string username)
{
Instance.Username = username;
return this;
}
public AuthenticationBuilder WithPassword(string password)
{
Instance.Password = password;
return this;
}
}
public abstract class BaseBuilder<T> where T : class
{
protected abstract T Instance { get; }
// Implicit conversion from `BaseBuilder<T>` to the final `T` object
public static implicit operator T(BaseBuilder<T> builder)
{
return builder.Build();
}
public virtual T Build()
{
return Instance;
}
}
// Models
public class Authentication
{
public string? Username { get; set; }
public string? Password { get; set; }
}
public class User
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public int Age { get; set; }
public Authentication? Authentication { get; set; }
}
public static class TestHelper
{
public static User BuildUserWithAuthentication(Action<UserBuilder>? userBuilder = null)
{
// Default user
UserBuilder user = new UserBuilder()
.WithFirstName("John")
.WithLastName("Doe")
.WithAge(25)
.WithAuthentication(
new AuthenticationBuilder()
.WithUsername("john")
.WithPassword("password123")
);
// Apply overrides if any
userBuilder?.Invoke(user);
return user.Build();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment