我现在有一些空闲时间,正在努力理解DI和IoC容器。我选择了Unity,没有任何原因,仅仅是从我所知道的来看,各个主要框架之间没有太大的区别,我希望起步时不必过于担心。随着事情变得更加复杂,我意识到我可能需要改变,但现在我希望它能够胜任。
所以,我正在处理一个相对简单的数据访问场景,并实现了以下接口和数据访问类。
public interface IEventRepository
{
IEnumerable<Event> GetAll();
}
public class EventRepository : IEventRepository
{
public IEnumerable<Event> GetAll()
{
// Data access code here
}
}
然后我可以按照以下步骤操作。
IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(IEventRepository), typeof(EventRepository));
var eventRepo = container.Resolve<IEventRepository>();
eventRepo.GetAll();
如果在六个月内需要更改我的数据库提供商,从我的理解中我需要创建IEventRepository的一个新实现并更新类型注册,这很好。
现在,我感到困惑的地方是:例如,如果我想要实现一些缓存,我可以继承适当的IEventRepository实现,并覆盖适当的方法以实现必要的缓存。但是,这样做将使使用通过DI传递的Moq实现测试缓存是否正常工作变得更加困难,所以为了真正实践DI的精神,我认为创建一个IEventRepository实现,然后使用DI请求一个实际的数据访问IEventRepository实现会更有意义。
public class CachedEventRepository : IEventRepository
{
private readonly IEventRepository _eventRepo;
public CachedEventRepository(IEventRepository eventRepo)
{
if (eventRepo is CachedEventRepository)
throw new ArgumentException("Cannot pass a CachedEventRepository to a CachedEventRepository");
_eventRepo = eventRepo;
}
public IEnumerable<Event> GetAll()
{
// Appropriate caching code ultimately calling _eventRepo.GetAll() if needed
}
}
这样做有意义吗?还是我做错了?你有什么建议?如果我做得正确,那么我该如何解决以下情况,以便CachedEventRepository获得适当的IEventRepository数据访问实现?
IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(IEventRepository), typeof(EventRepository));
container.RegisterType(typeof(IEventRepository), typeof(CachedEventRepository));
var eventRepo = container.Resolve<IEventRepository>();
eventRepo.GetAll();
非常感谢您的帮助。
编辑1 以下是我希望能够执行的Moq测试,我认为这不可能使用继承来实现,需要使用DI。
var cacheProvider = new MemoryCaching();
var eventRepo = new Mock<IEventRepository>(MockBehavior.Strict);
eventRepo
.Setup(x => x.GetAll())
.Returns(() =>
{
return new Event[] {
new Event() { Id = 1},
new Event() { Id = 2}
};
});
var cachedEventRepo = new CachedEventRepository(
eventRepo.Object,
cacheProvider);
var data = cachedEventRepo.GetAll();
data = cachedEventRepo.GetAll();
data = cachedEventRepo.GetAll();
Assert.IsTrue(data.Count() > 0);
eventRepo.Verify(x => x.GetAll(), Times.Once());
// This set method should expire the cache so next time get all is requested it should
// load from the database again
cachedEventRepo.SomeSetMethod();
data = cachedEventRepo.GetAll();
data = cachedEventRepo.GetAll();
Assert.IsTrue(data.Count() > 0);
eventRepo.Verify(x => x.GetAll(), Times.Exactly(2));