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)
{
...
精彩评论