Tim Skauge
Tim Skauge

Reputation: 1844

Custom construction with open generics in StructureMap

I know that for structuremap you can register generic types by specifying the following:

StructureMapConfiguration 
   .For(typeof(IRepository<>)) 
   .Use(typeof(RepositoryImplementation<>));

When ObjectFactory.GetInstance<IRepository<Entity>>() is called the corresponding implementation is returned RepositoryImplementation<Entity>.

But what if I want a wrapped version of the repository? A version that also implements IRepository<Entity> - lets say CachedRepository<Entity> that has a constructor that takes an implementation of IRepository<TEntity> ctor: CachedRepository(IRepository<Entity> innerRepository).

How do I get structuremap to return CachedRepository<Entity> when asking for an IRepository with the concreate RepositoryImplementation as innerRepository?

Upvotes: 0

Views: 278

Answers (2)

Joshua Flanagan
Joshua Flanagan

Reputation: 8557

One approach is to create a custom type interceptor:

public class CacheMyRepos : TypeInterceptor
{
    private readonly Type _openTargetType;
    private readonly Type _openWrapperType;

    public CacheMyRepos(Type openTargetType, Type openWrapperType)
    {
        _openTargetType = openTargetType;
        _openWrapperType = openWrapperType;
    }

    public object Process(object target, IContext context)
    {
        var closedWith = target.GetType().GetGenericArguments()[0];
        var closedWrapperType = _openWrapperType.MakeGenericType(closedWith);
        return Activator.CreateInstance(closedWrapperType, target);
    }

    public bool MatchesType(Type type)
    {
        return type.ImplementsInterfaceTemplate(_openTargetType);
    }
}

And then register it with:

var container = new Container(x =>
{
    x.For(typeof (IRepository<>)).Use(typeof (RepositoryImplementation<>));
    x.RegisterInterceptor(
      new CacheMyRepos(typeof(IRepository<>), typeof(CachedRepository<>)));
});

Upvotes: 1

Joshua Flanagan
Joshua Flanagan

Reputation: 8557

Does CachedRepository<Entity> have to work with any concrete implementation, or is it safe to tie it to RepositoryImplementation<Entity>? If it can be tied, this should do the trick:

StructureMapConfiguration
   .For(typeof(IRepository<>)) 
   .Use(typeof(CachedRepository<>));

Then change the CachedRepository constructor to CachedRepository(RepositoryImplementation<Entity> innerRepository).

Upvotes: 0

Related Questions