Skip to content

Instantly share code, notes, and snippets.

@jansabbe
Last active June 29, 2020 05:50
Show Gist options
  • Save jansabbe/78d624c053e44843c2c3a173e682c22e to your computer and use it in GitHub Desktop.
Save jansabbe/78d624c053e44843c2c3a173e682c22e to your computer and use it in GitHub Desktop.
Generic With method builder
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Xunit;
namespace Tjoelala
{
public class Person
{
public string Name { get; private set; }
public string FirstName { get; set; }
public string FullName => $"{FirstName} {Name}";
public int Age { get; set; }
public List<Person> Kids { get; private set; } = new List<Person>();
private Person() { }
public Person(string name)
{
Name = name;
}
}
public class PersonBuilder : ObjectBuilder<Person, PersonBuilder>
{
public PersonBuilder()
{
With(x => x.Name, "Bos")
.With(x => x.FirstName, "Jos")
.With(x => x.Age, 44);
}
public PersonBuilder WithKids(int nbOfKids)
{
var kids = Enumerable.Range(0, nbOfKids)
.Select(i => new PersonBuilder()
.With(t => t.FirstName, $"kid{i}")
.With(t => t.Age, 14)
.Build())
.ToList();
return With(t => t.Kids, kids);
}
}
public class UnitTest1
{
[Fact]
public void Test1()
{
var person = new PersonBuilder()
.With(t => t.FirstName, "Albert")
.With(t => t.Name, "Bosje")
.WithKids(3)
.Build();
Assert.Equal("Albert Bosje", person.FullName);
Assert.Equal(3, person.Kids.Count);
}
}
#region Object builder stuff
public abstract class ObjectBuilder<TObject, TBuilder> where TBuilder : ObjectBuilder<TObject, TBuilder> where TObject : class
{
private readonly Dictionary<PropertyInfo, object> _values = new Dictionary<PropertyInfo, object>();
public virtual TObject Build()
{
var obj = Activator.CreateInstance(typeof(TObject), true) as TObject;
foreach (var kvp in _values)
{
var pi = kvp.Key;
var value = kvp.Value;
pi.SetValue(obj, value);
}
return obj;
}
public TBuilder With<TProp>(Expression<Func<TObject, TProp>> expr, TProp value)
{
var body = expr.Body as MemberExpression;
var property = body.Member as PropertyInfo;
_values[property] = value;
return this as TBuilder;
}
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment