2017-02-15 5 views
0

Я пытаюсь настроить контейнер для регистрации класса, который принимает в своем конструкторе IDictionary<string, IInterface>, поэтому в моем IoC я хотел бы знать, как получить именованный экземпляр (если эта функция доступна в SI). Примером чего я хочу достичь:Словарь SimpleInjector как аргумент конструктора

container.Register<IOtherInterface>(() => 
    new OtherInterface(new Dictionary<string, IInterface> 
    { 
     { "a", container.GetInstance<IInterface>("named-a") }, 
     { "b", container.GetInstance<IInterface>("named-b") }, 
    }); 

Есть ли способ настроить это?

Обновлено:

Реализация интерфейса и тот же объект с разными параметрами и пример, который я не смог увидеть в документации SI https://simpleinjector.readthedocs.io/en/latest/howto.html#resolve-instances-by-key. Я хотел бы избежать того факта, что мне нужно создать новый интерфейс (.. с соответствующими параметрами ...) для каждого значения в словаре, поэтому я подумал, что обозначение регистрации было чем-то доступным в SI.

Возможно, мой подход неправильный, и я должен попытаться установить зависимости по-другому.

Пример использования:

public class OtherInterface : IOtherInterface 
{ 
    private readonly IDictionary<string, IInterface> _interfces; 

    public OtherInterface(IDictionary<string, IInterface> interfaces) 
    { 
     _interfaces = interfaces; 
    } 

    public void DoSomething(MyRequest request) 
    { 
     if(_interfaces.ContainKey(request.SelectMyInterface)) 
     { 
      _interfaces[request.SelectMyInterface].DoSpecificStuff(); 
     } 
    } 
} 

Я мог бы потенциально расширить интерфейс IInterface и применить шаблон стратегии здесь имея метод, как Applies(string type), но я использовал словарный подход в прошлом с Ninject.

+0

Существует довольно обширная документация о регистрациях с ключами, словарях и фабриках [здесь] (https://simpleinjector.readthedocs.io/en/latest/howto.html#resolve-instances-by-key). Если эта документация не отвечает на ваш вопрос, уточните свой вопрос с более подробной информацией (и не забудьте оставить комментарий, чтобы уведомить всех читателей о том, что ваш вопрос изменился). – Steven

+0

Обновлено с фактическим сценарием, который у меня есть. Я уже читал о регистрациях с ключами, но не смог найти ничего связанного с этим конкретным случаем. –

+0

Как «OtherInterface» определяет, когда использовать 'named-a' или' named-b'? Как определить ключи 'a' и' b'? – Steven

ответ

1

Keyed регистрация выполняется в простом Injector путем создания InstanceProducer экземпляры «вручную» следующий образом:

var a = Lifestyle.Transient.CreateProducer<IInterface, A>(container); 
var b = Lifestyle.Transient.CreateProducer<IInterface, B>(container); 

Использования этих производителей Например, вы можете сделать словарную регистрацию следующим образом:

container.Register<Dictionary<string, IInterface>(() => new Dictionary<string, IInterface> 
{ 
    { "a", a.GetInstance() }, 
    { "b", b.GetInstance() }, 
}); 

Вашим OtherInterface выглядит как диспетчер для меня. Если это только задание - направить входящий запрос, я бы сказал, что все в порядке.

Но вместо того, чтобы впрыскивать словарь с полным списком созданных экземпляров, я хотел бы предложить несколько иную конструкцию:

public class OtherInterface : IOtherInterface 
{ 
    private readonly IDictionary<string, Func<IInterface>> _interfces; 

    public OtherInterface(IDictionary<string, Func<IInterface>> interfaces) { 
     _interfaces = interfaces; 
    } 

    public void DoSomething(MyRequest request) => 
     _interfaces[request.SelectMyInterface].Invoke().DoSpecificStuff(); 
} 

Здесь словарь содержит Func<IInterface>. Таким образом, реализация может быть создана «на лету», без необходимости создавать все реализации при каждом вызове.

Вы можете зарегистрировать это следующим образом:

container.RegisterSingleton<IOtherInterface>(new OtherInterface(
    new Dictionary<string, Func<IInterface>> 
    { 
     { "a", CreateProducer<A>() }, 
     { "b", CreateProducer<B>() }, 
    }); 

private Func<IInterface> CreateProducer<T>() where T : IInterface => 
    Lifestyle.Transient.CreateProducer<IInterface, T>(this.container).GetInstance; 

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

+0

Мне очень нравится подход Func! Я бы предположил, что все экземпляры будут созданы только в первый раз, когда приложение загрузится, потому что у OtherInterface будет LifeStyle.Singleton? –

+0

@CarlosTorrecillas: Независимо от того, является ли 'OtherInterface' * Singleton *, в этом случае не имеет значения, поскольку' Func 'переадресует вызов обратно в контейнер для каждого вызова. Это означает, что образ жизни фабричных экземпляров сохраняется, хотя 'OtherInterface' является * Singleton *. – Steven

+0

Вижу, спасибо за объяснение! –

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