Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StructureMap OnCreation with generic types

Hi I would like to call method Foo after StructureMap creates instance of repository, so there is a method for that, called OnCreation.

x.For(typeof(IRepository<>))
 .Use(typeof(Repository<>))
 .OnCreation((ctx, instance) => { instance.Foo() });

But compiler of course can't infer the type, so I tried to supply the generic type like this:

x.For(typeof(IRepository<>))
 .Use(typeof(Repository<>))
 .OnCreation<Repository<>>((ctx, instance) => { instance.Foo() });

This won't compile, it would not even parse(Invalid expression term '>). I tried to build Action object by myself but with no luck. Then I found about InstanceInterceptor, so I've written a class, but I can't figure how to plugin it in. There should be InterceptWith method, but it is not available for ConfiguredInstance which is result type of not generic Use method.

I know I can HACK that in many other ways but i would like to do it within StructureMap mapping.

Please help :)

like image 456
tekado Avatar asked Aug 02 '26 15:08

tekado


1 Answers

If your Foo() method does not require access to the generic type then you could abstract this into a different interface:

public interface IRepository
{
    void Foo();
}

public interface IRepository<T> : IRepository
{
}

public class Repository<T> : IRepository<T>
{
    public void Foo()
    {

    }
}

Then to configure StructureMap:

cfg.For(typeof(IRepository<>)).Use(typeof(Repository<>))
    .OnCreation<IRepository>((ctx, handler) =>
{
    handler.Foo();
});

Things get incredibly tricky with open generic types and I've often found that it's easier to hand additional initialization logic off to a factory. Rather than injecting an IRepository<T>, inject a IRepositoryFactory<T> that can perform any additional initialization you need (you could still inject IRepository<T> into your factory if you don't like the static StructureMap reference):

public interface IRepositoryFactory<T>
{
    IRepository<T> Create();
}

public class RepositoryFactory<T> : IRepositoryFactory<T>
{
    public IRepository<T> Create()
    {
        var repo = ObjectFactory.GetInstance<IRepository<T>>();
        repo.Foo();

        return repo;
    }
}
like image 154
Ben Foster Avatar answered Aug 09 '26 14:08

Ben Foster