c# 将 DRY 标准应用于多个类

  • 本文关键字:应用于 标准 DRY c# dry
  • 更新时间 :
  • 英文 :


我目前正在做一个项目,里面有很多从基类继承的类。 这是在一个测试项目中。基类如下所示:

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 });

最新更新