I am working on a project at the moment with a lot of classes that inherit from a base class. This is in a test project. The base class looks like this:
public class DatabaseContextContext
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
public static DatabaseContextContext GivenServices() => new DatabaseContextContext();
public void WhenList<T>(List<T> response) where T: class
{
DatabaseContext.Set<T>().Returns(response.AsQueryable());
}
}
And then there is another class that looks like this:
public class VenuesContext: DatabaseContextContext
{
public IMediator Mediator;
protected VenuesContext()
{
Mediator = Substitute.For<IMediator>();
}
public VenuesContext WhenListSucceeds(List<Venue> venues)
{
WhenList(venues);
return this;
}
}
And another like this:
public class TheatresContext: DatabaseContextContext
{
public IMediator Mediator;
protected TheatresContext()
{
Mediator = Substitute.For<IMediator>();
}
public TheatresContext WhenListSucceeds(List<Theatre> theatres)
{
WhenList(theatres);
return this;
}
}
As you may have guessed, this is a simple version, there are hundreds of these classes and some are much more complicated, but the idea is the same. Anyway, I want to try to remove some of the repeated code, namely:
public ListVenuesContext WhenListSucceeds(List<Venue> venues)
{
WhenList(venues);
return this;
}
Currently you can chain the methods together like this:
var services = VenuesContext.GivenServices().WhenListSucceeds(new List<Venue>());
and I would like to keep that functionality. I tried to do something like this:
public TReturn WhenList<T, TReturn>(List<T> response) where T: class where TReturn: class, new()
{
DatabaseContext.Set<T>().Returns(response.AsQueryable());
return new TReturn();
}
But I am not sure this is right because I have to call new TReturn()
instead of this
.
Also, the chain changes to this:
var services = VenuesContext.GivenServices().WhenList<Venue, ListVenuesContext>(new List<Venue>());
Which isn't terrible, but it would be nice to not have to add <Venue, ListVenuesContext>
to each call.
Can anyone think of a more elegant solution?
Update
I may have found a solution by using http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx
If I change the DatabaseContextContext to this:
public class DatabaseContextContext<T> where T: DatabaseContextContext<T>
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
public T WhenList<TM>(List<TM> response) where TM : class
{
DatabaseContext.Set<TM>().Returns(response.AsQueryable());
return (T)this;
}
}
Then I can do something like this:
public class ListVenuesContext : DatabaseContextContext<ListVenuesContext>
{
public static ListVenuesContext GivenServices() => new ListVenuesContext();
public ListVenuesHandler WhenCreateHandler() => new ListVenuesHandler(DatabaseContext);
}
which will allow me to invoke like this:
var services = ListVenuesContext.GivenServices().WhenList(new List<Venue>());
The only problem I can see with this, is that I can't inherit multiple times. For example:
public class ListVenuesContext : VenuesContext
{
public static ListVenuesContext GivenServices() => new ListVenuesContext();
public ListVenuesHandler WhenCreateHandler() => new ListVenuesHandler(DatabaseContext);
}
public class VenuesContext: DatabaseContextContext<VenuesContext>
{
public IMediator Mediator;
protected VenuesContext()
{
Mediator = Substitute.For<IMediator>();
}
public void WhenGet(Venue venue)
{
Mediator.Send(Arg.Any<GetVenue>()).Returns(Attempt<Venue>.Succeed(venue));
}
}
Sorted it. I did use the solution above, but I did it like this:
public class DatabaseContextContext<T> where T: DatabaseContextContext<T>
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
public T WhenListSucceeds<TM>(List<TM> response) where TM : class
{
DatabaseContext.Set<TM>().Returns(response.AsQueryable());
return (T)this;
}
public T WhenGetSucceeds<TM>(TM response) where TM : class
{
DatabaseContext.Set<TM>().Returns(new List<TM> {response}.AsQueryable());
return (T)this;
}
}
If there was a class that others inherited from that also inherited from the DatabaseContextContext, I could do it like this:
public class MediatorContext<T>: DatabaseContextContext<T> where T: MediatorContext<T>
{
public IMediator Mediator;
protected MediatorContext()
{
Mediator = Substitute.For<IMediator>();
}
}
And then the child class could inherit that, like this:
public class DeleteVenueContext : MediatorContext<DeleteVenueContext>
{
public static DeleteVenueContext GivenServices() => new DeleteVenueContext();
public DeleteVenueHandler WhenCreateHandler() => new DeleteVenueHandler(DatabaseContext, Mediator);
}
Which meant I could still use my chaining like this:
var services = DeleteVenueContext.GivenServices().WhenGetSucceeds(new Venue { Id = id });