开发者

Automatically resolve Interface<T> to Implementation<T> in StructureMap (differ only by generic type T)

开发者 https://www.devze.com 2023-02-06 06:52 出处:网络
I have an interface (IRepository<T>) that is currently being extended for each specific repository, ie: IUserRepository : IRepository<User>.

I have an interface (IRepository<T>) that is currently being extended for each specific repository, ie: IUserRepository : IRepository<User>.

Each of these interfaces has corresponding concrete classes, ie: UserRepository : Repository<User>, IUserRepository.

These individual repositories don't add any additional functionality, they are all empty interfaces/classes that are used simply to pass the generics around.

I use StructureMap to resolve IUserRepository into UserRepository using a Registry with an assembly scanner and some naming conventions.

I'd like this to move to a way more optimised state, where instead of passing around instances of IUserRepository and getting it resolved to UserRepository, I can pass around IRepository<User> and have it resolved to Repository<User>.

This would remove the need to create these extra empty interfaces and classes.

I can't work out a way to use StructureMap's configuration to setup this generic mapping. Something like this:

For(typeof(IRepository<>).Use(typeof(Repository<>)).WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter();

Edit

After getting the first couple of answers, I want to clarify this a bit more.

I don't want to create individual classes for the For bit of the configuration. I want to have the following classes/interfaces in my code:

  • IRepository<T> where T : Entity
  • Repository<T> : IRepository<T> where T : Entity
  • Person : Entity
  • Product : Entity
  • Order : Entity
  • Whatever : Entity

And have the following mappings achieved with convention:

IRepository<Person> => Repository<Person>
IRepository<Product> => Repository<Product>
IRepository<Order> => Repository<Order>
IRepository<Whatever> => Repository<Whatever>

But I do not want to have to create a mapping for each one, ala:

For<IRepository&开发者_如何转开发lt;Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

I want a single mapping that will work for any IRepository:

For<IRepository<>>().Use<Repository<>>().WithTheSameGenericType();

I would then use this to inject the repositories into services:

public MyService(IRepository<User> userRepository)

And expect that to be resolved to a Repository<User> at runtime.


Turns out there is no fancy method to call, or no fancy wiring to do, you just use For and Use (the non generic versions):

public class DataRegistry : Registry
{
    public DataRegistry()
    {
        For(typeof (IRepository<>)).Use(typeof(Repository<>));
    }
}

When I inject a IRepository<Person> it is being resolved as a Repository<Person> now.

I encountered error 104 saying Repository wasn't pluggable for IRepository. This was because Repository was marked abstract. Making it non-abstract fixed that error and it is working as desired.


I suggest you to take a look at the AddAllTypesOf method. I had some similar code and achieved my objectives by using it (and kept the auto register feature working).

In your case, you should just change

For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

to

AddAllTypesOf(typeof(IRepository<>));

In the end, your container will be similar to:

return new Container(x =>
        {
            x.Scan(y =>
            {
                y.TheCallingAssembly();
                y.AddAllTypesOf(typeof(IRepository<>));
                y.WithDefaultConventions();
            });
        });


Here is an example. Structure map will allow you to do both also.

 //IRepository
 For<IMemberRepository>().Add<MemberRepository>();

 //IRepository<T>
 For<IRepository<Member>>().Add<MemberRepository>();

Then it is useful to ask for the types by just knowing the generic type at runtime:

Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType);
IocResolve.Resolve(repositoryType);


http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/12/17/advanced-structuremap-connecting-implementations-to-open-generic-types.aspx


Have a look at IRegistrationConvention interface.

public class DomainRegistry : Registry
{
    public DomainRegistry()
        : base()
    {
        Scan(y =>
        {
            y.AssemblyContainingType<IRepository>();
            y.Assembly(Assembly.GetExecutingAssembly().FullName);
            y.With(new RepositoryTypeScanner());
        });

Where RepositoryTypeScanner:

public class RepositoryTypeScanner : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
      ...
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号