2016-05-30 2 views
1

Допустим, что у меня есть две службы, которые зависят от одного интерфейса:Регистрация декораторы, основанные на потребителей с помощью простого инжектора

class Service1 
{ 
    ... 
    Service1(IDependency dependency) { ... } 
    ... 
} 

и

class Service2 
{ 
    ... 
    Service2(IDependency dependency) { ... } 
    ... 
} 

IDependency зарегистрирован какой-либо конкретной реализации. Как я могу зарегистрировать декоратор для реализации IDependency, который может быть использован только Service2? Другими словами, Идентификация должна быть разрешена к экземпляру декоратора только внутри Service2. Является ли это возможным?

+0

См: https://simpleinjector.readthedocs.io/en/latest/advanced.html#applying-decorators-conditionally-based-on-consumer – Steven

ответ

2

Вы можете использовать context-based injection

// Register decorators first 
container.RegisterConditional<IDependency, DependencyDecorator1>(
    c => c.Consumer.ImplementationType == typeof(Service1)); 
container.RegisterConditional<IDependency, DependencyDecorator2>(
    c => c.Consumer.ImplementationType == typeof(Service2)); 

// Register the real implementation last using !c.Handled 
container.RegisterConditional<IDependency, RealImplementationDependency>(
    c => !c.Handled); 

Смотрите примечание из документации:

Примечание: Во многих случаях инъекции контекст на основе не является лучшим решением, и дизайн должны быть перепроверены. В некоторых узких случаях, однако, это имеет смысл .

В качестве альтернативы вы можете получить отдельные интерфейсы, которые расширяют IDependency и использовать их по одному для каждой службы. Это может быть более подходящим для дифференциации зависимостей. В этом случае вы просто регистрируете разные реализации/экземпляры для каждого интерфейса.

Например, у вас может быть абстракция хранилища файлов против службы облачного хранилища. Основной интерфейс инкапсулирует все действия по хранению файлов, а затем расширяет его для определенных ковшей в контейнере хранения. Вы можете предоставить единую реализацию (через регистрацию делегата), которая берет ведро хранилища в качестве параметра конструктора для каждого именованного интерфейса. Использование именованных интерфейсов, которые идентифицируют цель в ковше, повышает понимание кода.

public interface IFileStorage 
{ 
     ... 
} 

public interface IUploadStorage : IFileStorage { /* empty interface */ } 

public interface IContentStorage : IFileStorage { /* empty interface */ } 

public class FileStorage : IUploadStorage, IContentStorage 
{ 
     public FileStorage(string containerName) { ... } 
     ... 
} 

public UploadService(IUploadStorage storage) 
{ 
    ... 
} 

public ContentService(IContentStorage storage) 
{ 
    ... 
} 


container.Register<IUploadStorage>(() = new FileStorage(Containers.Upload)); 
container.Register<IContentStorage>(() = new FileStorage(Containers.Content)); 
+0

Я не могу это сделать, потому что если я лечу DependencyBar как декоратор над DependencyFoo, это поставит меня в ситуацию, когда DependencyBar зависит от самого себя. –

+0

Использование расширенных задержек для дифференциации зависимостей в моем случае отлично работало. Это был прекрасный ответ, который я искал. Спасибо вам за ваши ответы. –

+0

Одна из сторон создания двух интерфейсов ограничена/сложнее. Например, что, если вы хотите украсить эти типы? Вам нужно будет создать два похожих декоратора. –

Смежные вопросы