То, чего вы пытаетесь достичь, невозможно. Это не ограничение используемого контейнера DI, а скорее ограничение системы типов. NET. Я часто советую разработчикам, испытывающим проблемы с DI, для понимания, удалить контейнер DI из уравнения и вместо этого построить графы объектов вручную. Это хорошо работает в вашей ситуации, как я продемонстрирую ниже.
Предположим, у вас есть IMyClassRepository
потребитель:
public class RepoConsumer
{
RepoConsumer(IMyClassRepository repo) ...
}
И IMyClassRepository
реализация:
public class MyClassRepositoryImpl : IMyClassRepository
{
...
}
Теперь давайте создадим граф объектов для RepoConsumer
, который использует AuditRepositoryDecorator<MyClass>
:
var repo = new MyClassRepositoryImpl();
var decoratedRepo = new AuditRepositoryDecorator<MyClass>(repo);
var consumer = new RepoConsumer(decoratedRepo); // <-- COMPILE ERROR
Когда вы скомпилируете этот код, вы заметите, что компилятор C# сгенерирует ошибку строка new RepoConsumer
. Это потому, что RepoConsumer
ожидает IMyClassRepository
. Хотя MyClassRepositoryImpl
реализует IMyClassRepository
, AuditRepositoryDecorator<MyClass>
не реализует IMyClassRepository
.
Чтобы решить эту проблему, вы можете попробовать разрешить AuditRepositoryDecorator<T>
реализовать IMyClassRepository
, но это будет очевидно, будет некрасиво, потому что декоратор должен будет реализовать дюжину интерфейсов для каждого объекта в вашей системе.
Но это упражнение доказывает, что проблема не столько в контейнере DI, сколько в что система типов просто не позволяет вам построить граф этого объекта. А поскольку система типов не позволяет этого, контейнер DI определенно не позволит этого. Он не может обойти проверку типов в системе типов. К счастью.
Но решение вашей проблемы на самом деле действительно простое: удалите указанные c IMyClassRepository
и позвольте потребителям зависеть от IWriteRepository<MyClass>
. Это может показаться неутешительным решением, но существует множество проблем, связанных с производством от общих c интерфейсов. Просто примите тот факт, что потребители зависят от такой обобщенной c абстракции. Это займет некоторое время, но со временем вы начнете любить и ценить этот стиль программирования.
Но, конечно, это все еще оставляет нам вопрос о том, как добавить новые методы, такие как MyClass Get(string)
. Существует несколько решений, таких как:
- Реализовать его как метод расширения (возможно только тогда, когда сам метод требует доступа к самому интерфейсу, а не к внутренним компонентам класса)
- Определить отдельный интерфейс, что может быть хорошей идеей в целом, в соответствии с Принципом разделения интерфейсов