我正在尝试使用SM和泛型在我的存储库层中实现策略模式。为此,我有一个接口,IPocoRepository,它具有使用Entity Framework的具体实现。我已经设法在我的Bootstrapper文件中连线:
For(typeof(IPocoRepository<>)).Use(typeof(EntityFrameworkRepository<>));
当我尝试为此接口实现缓存时,会出现问题。在我的缓存类中,我想要一个基本存储库类的实例,这样我就可以保持我的设计DRY。让我概述这三个文件的外观:
public interface IPocoRepository<T>
{
IQueryable<T> GetAll();
...
public class EntityFrameworkRepository<T> : IPocoRepository<T> where T : class
{
public IQueryable<T> GetAll()
{
...
public class CachedRepository<T> : IPocoRepository<T> where T : class
{
private IPocoRepository<T> _pocoRepository;
public CachedRepository(IPocoRepository<T> pr)
{
_pocoRepository = pr;
}
public IQueryable<T> GetAll()
{
var all = (IQueryable<T>)CacheProvider.Get(_cacheKey);
if (!CacheProvider.IsSet(_cacheKey))
{
all = _pocoRepository.GetAll();
...
编辑:我希望StructureMap在请求IPocoRepository时返回CachedRepository,除非在CachedRepository 中请求时 - 然后我希望它返回EntityFrameworkRepository。
我知道在处理非泛型类时这很简单:
For<ICountyRepository>().Use<CachedCountyRepository>()
.Ctor<ICountyRepository>().Is<CountyRepository>();
我尝试在文档中搜索如何执行此操作,但找不到任何内容。任何帮助将不胜感激!
答案 0 :(得分:2)
好的,这不是太难。您可以使用类型拦截器。鉴于您有以下课程:
public interface IRepository<T>{}
public class Repository<T>:IRepository<T>{}
public class RepositoryCache<T> : IRepository<T>
{
private readonly IRepository<T> _internalRepo;
public RepositoryCache(IRepository<T> internalRepo)
{
_internalRepo = internalRepo;
}
public IRepository<T> InternalRepo
{
get { return _internalRepo; }
}
}
然后,您需要创建一个类型拦截器。您可以使用StructureMap提供的可配置“MatchedTypeInterceptor”。拦截器需要查找您的存储库,然后找出泛型类型参数是什么。一旦它具有类型参数,它就可以声明它需要的缓存类型并初始化它。作为初始化的一部分,它将在其构造函数中使用原始存储库。然后拦截器将完成的缓存返回到来自ioc上下文的任何请求。这是测试中的完整序列。
这可以移到您的注册表中,我只是将它们放在一起作为一个最小的例子。
[Test]
public void doTest()
{
MatchedTypeInterceptor interceptor = new MatchedTypeInterceptor(
x => x.FindFirstInterfaceThatCloses(typeof (IRepository<>)) != null);
interceptor.InterceptWith(original =>
{
Type closedType = original.GetType()
.FindFirstInterfaceThatCloses(typeof(IRepository<>));
var genericParameters = closedType.GetGenericArguments();
var closedCacheType = typeof(RepositoryCache<>)
.MakeGenericType(genericParameters);
return Activator.CreateInstance(closedCacheType, new[] {original});
});
ObjectFactory.Initialize(x =>
{
x.For(typeof (IRepository<>)).Use(typeof (Repository<>));
x.RegisterInterceptor(interceptor);
});
var test = ObjectFactory.GetInstance<IRepository<int>>();
Assert.That(test is RepositoryCache<int>);
}