我目前正在做一个项目,里面有很多从基类继承的类。 这是在一个测试项目中。基类如下所示:
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());
}
}
然后还有另一个类看起来像这样:
public class VenuesContext: DatabaseContextContext
{
public IMediator Mediator;
protected VenuesContext()
{
Mediator = Substitute.For<IMediator>();
}
public VenuesContext WhenListSucceeds(List<Venue> venues)
{
WhenList(venues);
return this;
}
}
另一个像这样:
public class TheatresContext: DatabaseContextContext
{
public IMediator Mediator;
protected TheatresContext()
{
Mediator = Substitute.For<IMediator>();
}
public TheatresContext WhenListSucceeds(List<Theatre> theatres)
{
WhenList(theatres);
return this;
}
}
您可能已经猜到了,这是一个简单的版本,有数百个这样的类,有些要复杂得多,但想法是相同的。 无论如何,我想尝试删除一些重复的代码,即:
public ListVenuesContext WhenListSucceeds(List<Venue> venues)
{
WhenList(venues);
return this;
}
目前,您可以像这样将方法链接在一起:
var services = VenuesContext.GivenServices().WhenListSucceeds(new List<Venue>());
我想保留该功能。 我尝试做这样的事情:
public TReturn WhenList<T, TReturn>(List<T> response) where T: class where TReturn: class, new()
{
DatabaseContext.Set<T>().Returns(response.AsQueryable());
return new TReturn();
}
但我不确定这是对的,因为我必须打电话给new TReturn()
而不是this
。 此外,链条更改为:
var services = VenuesContext.GivenServices().WhenList<Venue, ListVenuesContext>(new List<Venue>());
这并不可怕,但不必为每个呼叫添加<Venue, ListVenuesContext>
会很好。
谁能想到更优雅的解决方案?
<小时 />更新
我可能已经通过使用 http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx 找到了解决方案
如果我将DatabaseContextContext更改为:
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;
}
}
然后我可以做这样的事情:
public class ListVenuesContext : DatabaseContextContext<ListVenuesContext>
{
public static ListVenuesContext GivenServices() => new ListVenuesContext();
public ListVenuesHandler WhenCreateHandler() => new ListVenuesHandler(DatabaseContext);
}
这将允许我像这样调用:
var services = ListVenuesContext.GivenServices().WhenList(new List<Venue>());
我能看到的唯一问题是我不能多次继承。例如:
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));
}
}
排序。我确实使用了上面的解决方案,但我这样做了:
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;
}
}
如果有一个类,其他人继承自该类也继承自DatabaseContextContext,我可以这样做:
public class MediatorContext<T>: DatabaseContextContext<T> where T: MediatorContext<T>
{
public IMediator Mediator;
protected MediatorContext()
{
Mediator = Substitute.For<IMediator>();
}
}
然后子类可以继承它,如下所示:
public class DeleteVenueContext : MediatorContext<DeleteVenueContext>
{
public static DeleteVenueContext GivenServices() => new DeleteVenueContext();
public DeleteVenueHandler WhenCreateHandler() => new DeleteVenueHandler(DatabaseContext, Mediator);
}
这意味着我仍然可以像这样使用我的链:
var services = DeleteVenueContext.GivenServices().WhenGetSucceeds(new Venue { Id = id });