c# 将 DRY 标准应用于多个 类
c# apply DRY standards to multiple classes
我目前正在做一个项目,其中有很多 class 继承自基础 class。
这是在一个测试项目中。基础 class 看起来像这样:
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());
}
}
然后还有一个 class 看起来像这样:
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;
}
}
你可能已经猜到了,这是一个简单的版本,有数百个这样的 classes,有些更复杂,但思路是一样的。
无论如何,我想尝试删除一些重复的代码,即:
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;
}
}
如果有一个 class 其他人继承自那个也继承自 DatabaseContextContext,我可以这样做:
public class MediatorContext<T>: DatabaseContextContext<T> where T: MediatorContext<T>
{
public IMediator Mediator;
protected MediatorContext()
{
Mediator = Substitute.For<IMediator>();
}
}
然后 child class 可以继承它,像这样:
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 });
我目前正在做一个项目,其中有很多 class 继承自基础 class。 这是在一个测试项目中。基础 class 看起来像这样:
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());
}
}
然后还有一个 class 看起来像这样:
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;
}
}
你可能已经猜到了,这是一个简单的版本,有数百个这样的 classes,有些更复杂,但思路是一样的。 无论如何,我想尝试删除一些重复的代码,即:
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;
}
}
如果有一个 class 其他人继承自那个也继承自 DatabaseContextContext,我可以这样做:
public class MediatorContext<T>: DatabaseContextContext<T> where T: MediatorContext<T>
{
public IMediator Mediator;
protected MediatorContext()
{
Mediator = Substitute.For<IMediator>();
}
}
然后 child class 可以继承它,像这样:
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 });