使用泛型和StructureMap实现策略模式

时间:2014-04-07 12:34:25

标签: c# generics dependency-injection structuremap

我正在尝试使用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>();

我尝试在文档中搜索如何执行此操作,但找不到任何内容。任何帮助将不胜感激!

1 个答案:

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