В моем слое доступа к данным у меня есть хранилище иерархии, которая выглядит следующим образом:Как сделать Simple Injector предпочтительными реализациями «самого производного» интерфейса?
<TEntity>
IEntityRepository<---------+ICustomerRepository
^ ^
| |
| |
| |
+ |
<TEntity> +
EntityRepository<----------+CustomerRepository
IEntityRepository<TEntity>
Интерфейс определяет основные операции CRUD, которые будут полезны независимо от типа объекта. EntityRepository<TEntity>
- это конкретная реализация этих операций.
Кроме того, существуют типы репозитория для операций, которые относятся к конкретному объекту. В приведенном выше примере у меня есть объект Customer
, а интерфейс ICustomerRepository
определяет операции, такие как GetByPhoneNumber
. ICustomerRepository
также получен из IEntityRepository<Customer>
, так что общие операции CRUD также будут доступны для экземпляра ICustomerRepository
. Наконец, CustomerRepository
- это конкретная реализация для операций ICustomerRepository
, и она также наследует от EntityRepository<Customer>
для реализации общих операций.
Итак, перейдем к моему фактическому вопросу: я использую Simple Injector для ввода экземпляров в свое приложение. Я регистрирую каждый из специализированных типов репозитория в моем контейнере: CustomerRepository
как реализация ICustomerRepository
и так далее.
Чтобы обеспечить новые типы объектов могут быть добавлены в систему и использовать без необходимости создания новой, конкретной реализации хранилища, а также, я хотел бы быть в состоянии служить по основанию EntityRepository<>
реализации, когда IEntityRepository<>
нового объекта является просил. Я понял, что могу использовать метод RegisterOpenGeneric
для этого.
Что я не могу понять, когда запрашивается общий репозиторий, как я могу обслуживать специализированный репозиторий для этого типа, если он существует, и общий репозиторий только в качестве резервной копии?
Например, предположим, что я делаю это в моем приложении:
container.Register<ICustomerRepository, CustomerRepository>();
container.RegisterOpenGeneric(typeof(IEntityRepository<>), typeof(EntityRepository<>));
Большинство классов, опирающихся на хранилищах будет просить ICustomerRepository
непосредственно. Тем не менее, может быть класса в моем приложении запрашивает базовый интерфейс, например:
public ContractValidator(IEntityRepository<Customer> customerRepository,
IEntityRepository<Contract> contractRepository)
{
...
Что происходит в приведенном выше примере:
customerRepository
получает экземплярEntityRepository<Customer>
contractRepository
получает примерEntityRepository<Contract>
Что я хочу сказать:
customerRepository
получает экземплярCustomerRepository
contractRepository
получает экземплярEntityRepository<Contract>
Есть ли способ сообщить разрешение Simple инжектора, что если вывод конкретного интерфейса существует, то это должно быть подано вместо?Поэтому для IDerived : IBase
запросы на IBase
должны вернуть реализацию IDerived
, если она существует. И я не хочу эту резолюцию по всем направлениям, только для этих репозиториев. Можно ли это сделать разумным образом, или мне нужно будет вручную перебирать все регистрационные данные в предикате и проверять вручную?
Это, кажется, разрешает это для меня. Подобно тому, как вы прокомментировали другой ответ, это действительно порождает проблему с порванным стилем жизни, и я могу получить несколько экземпляров репозитория в своем приложении. Я не считаю, что это может нанести какой-либо ущерб в моем случае, поскольку хранилища представляют собой тонкие абстракции над базовым поточно-безопасным сервисом, который имеет только один экземпляр. Но это все еще не идеально, и что-то нужно помнить о будущих изменениях архитектуры. Спасибо! –