I am trying to implement a complex builder to help my testing context. To do that I refactored my code to have a method :
public TestContext Add<T>(Action<IBuilder<T>> configurator) where T : class, new()
{
IBuilder<T> builder = CreateBuilderOf<T>();
configurator(builder);
T item = builder.GetItem();
RepositoryOf<T>().Insert(item);
SetCurrent(item);
return this;
}
The problem arises when I need to specify the configuration when calling the method :
TestContext.Instance.Add<Person>(personBuilder => ((PersonBuilder)personBuilder).Name("SMITH"));
I need to be able to use type specific methods in the configurator, which are implemented by the concrete builders, such as :
public PersonBuilder : IBuilder<Person>
{
private Person Item;
public PersonBuilder() { Item = new Person(); }
public Name(string mame) { Item.Name = name; }
public Person GetItem() { return Item; }
}
Apparently, passing an Action<PersonBuilder> as an Action<IBuilder<Person>> is not allowed, even though PersonBuilder implements IBuilder<Person>, hence the cast.
I would very much like to either :
- Need not to cast inside the lambda but rather at the start of it, e.g.
(PersonBuilder personBuilder) => personBuilder.Name("SMITH"), but that boils down to being an instance ofAction<PersonBuilder>and therefore is equally invalid; - Use a function such as
BuildSimplePerson(PersonBuilder builder)in Add's argument :Add<Person>(BuildSimplePerson)
I think I can do a type casting through two BuildSimplePersons implementations such as :
private void BuildSimplePerson(IBuilder<Person> builder)
{
BuildSimplePerson(builder as PersonBuilder);
}
private void BuildSimplePerson(PersonBuilder builder)
{
builder.Name("SMITH");
}
But that is not really an elegant solution.
I also realize passing Action<PersonBuilder> as an Action<IBuilder<Person>> is incorrect because we don't know if the argument to that function will truly be a PersonBuilder or any other implementation of IBuilder<Person>.
How can I do better ?