Автоматически разрешать интерфейс <T> для реализации <T> в StructureMap (отличаются только общим типом T)
У меня есть интерфейс (IRepository<T>
), который в настоящее время расширяется для каждого конкретного репозитория, то есть: IUserRepository : IRepository<User>
.
Каждый из этих интерфейсов имеет соответствующие конкретные классы, то есть: UserRepository : Repository<User>, IUserRepository
.
Эти отдельные репозитории не добавляют каких-либо дополнительных функций, это все пустые интерфейсы/классы, которые используются просто для передачи генериков.
Я использую StructureMap для решения IUserRepository
в UserRepository
, используя реестр со сборочным сканером и некоторыми соглашениями об именах.
Мне бы хотелось, чтобы это переместилось в более оптимизированное состояние, где вместо того, чтобы обходить экземпляры IUserRepository
и разрешать его до UserRepository
, я могу обойти IRepository<User>
и разрешить его Repository<User>
.
Это устранит необходимость создания этих дополнительных пустых интерфейсов и классов.
Я не могу разработать способ конфигурации StructureMap для настройки этого общего сопоставления. Что-то вроде этого:
For(typeof(IRepository<>).Use(typeof(Repository<>)).WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter();
Edit
После получения первой пары ответов я хочу уточнить это немного.
Я не хочу создавать отдельные классы для бита For
конфигурации. Я хочу иметь следующие классы/интерфейсы в моем коде:
-
IRepository<T> where T : Entity
-
Repository<T> : IRepository<T> where T : Entity
-
Person : Entity
-
Product : Entity
-
Order : Entity
-
Whatever : Entity
И получим следующие сопоставления с соглашением:
IRepository<Person> => Repository<Person>
IRepository<Product> => Repository<Product>
IRepository<Order> => Repository<Order>
IRepository<Whatever> => Repository<Whatever>
Но я не хочу создавать сопоставление для каждого из них, ala:
For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();
Я хочу одно сопоставление, которое будет работать для любого IRepository:
For<IRepository<>>().Use<Repository<>>().WithTheSameGenericType();
Затем я использовал бы это, чтобы внедрить репозитории в службы:
public MyService(IRepository<User> userRepository)
И ожидаем, что это будет разрешено для Repository<User>
во время выполнения.
Ответы
Ответ 1
Оказывается, нет никакого причудливого метода для вызова или нет подходящей проводки, вы просто используете For
и Use
(не общие версии):
public class DataRegistry : Registry
{
public DataRegistry()
{
For(typeof (IRepository<>)).Use(typeof(Repository<>));
}
}
Когда я вставляю a IRepository<Person>
, он решается теперь как Repository<Person>
.
Я столкнулся с ошибкой 104, говоря, что Repository не был подключен для IRepository. Это было потому, что хранилище было отмечено abstract
. При этом он не является абстрактным, фиксирует эту ошибку и работает по желанию.
Ответ 2
Я предлагаю вам взглянуть на метод AddAllTypesOf
. У меня был какой-то аналогичный код и я достиг своих целей, используя его (и сохранял функцию автоматического регистрации).
В вашем случае вы должны просто изменить
For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();
к
AddAllTypesOf(typeof(IRepository<>));
В конце концов, ваш контейнер будет похож на:
return new Container(x =>
{
x.Scan(y =>
{
y.TheCallingAssembly();
y.AddAllTypesOf(typeof(IRepository<>));
y.WithDefaultConventions();
});
});
Ответ 3
Вот пример. Структурная карта позволит вам сделать и то и другое.
//IRepository
For<IMemberRepository>().Add<MemberRepository>();
//IRepository<T>
For<IRepository<Member>>().Add<MemberRepository>();
Тогда полезно спросить типы, просто зная общий тип во время выполнения:
Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType);
IocResolve.Resolve(repositoryType);
Ответ 4
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/12/17/advanced-structuremap-connecting-implementations-to-open-generic-types.aspx
Ответ 5
Посмотрите интерфейс IRegistrationConvention.
public class DomainRegistry : Registry
{
public DomainRegistry()
: base()
{
Scan(y =>
{
y.AssemblyContainingType<IRepository>();
y.Assembly(Assembly.GetExecutingAssembly().FullName);
y.With(new RepositoryTypeScanner());
});
Где RepositoryTypeScanner:
public class RepositoryTypeScanner : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
...