Подтвердить что ты не робот

Могу ли я передать параметры конструктора методу Unity Resolve()?

Я использую Microsoft Unity для инъекции зависимостей, и я хочу сделать что-то вроде этого:

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryA и RepositoryB оба имеют конструктор, который принимает параметр IDataContext, и я хочу, чтобы Unity инициализировал репозиторий с помощью контекста, который я передал ему. Также обратите внимание, что IDataContext не зарегистрировано в Unity (я не хочу 3 экземпляра IDataContext).

4b9b3361

Ответ 2

< 2 центa >

Что делать, если позже вы решите использовать другую услугу, которая требует больше или меньше контекста?

Проблема с параметрами конструктора и IoC заключается в том, что параметры в конечном счете привязаны к используемому конкретному типу, а не к части контракта, который определяет интерфейс службы.

Мое предложение состояло в том, что вы также разрешаете контекст, и я считаю, что Unity должен иметь способ избежать построения трех экземпляров, или вы должны рассмотреть сервис factory, который может вам помочь построить объект.

Например, что, если позже вы решите создать репозиторий, который вообще не полагается на традиционную базу данных, но вместо этого используйте XML файл для создания фиктивных данных для теста? Как вы собираетесь загружать XML-контент в этот конструктор?

IoC основан на развязывании кода, связывая тип и семантику аргументов с конкретными типами, вы действительно не сделали развязки правильно, все еще есть зависимость.

"Этот код может разговаривать с любым типом репозитория, возможно, пока он реализует этот интерфейс... Ох и использует контекст данных".

Теперь я знаю, что для других контейнеров IoC есть поддержка для этого, и я использовал его в своей первой моей версии, но, на мой взгляд, это не относится к шагу разрешения.

</2 центa >

Ответ 3

Вы можете использовать InjectionConstructor/InjectionProperty/InjectionMethod в зависимости от вашей архитектуры впрыска в ResolvedParameter <T> ( "name" ), чтобы получить экземпляр предварительно зарегистрированного объекта в контейнере.

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

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));

Ответ 4

Спасибо, ребята... мой похож на пост от "Exist". См. Ниже:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

Ответ 5

Самый короткий ответ: нет. В настоящее время Unity не имеет возможности передавать параметры в конструктор, которые не являются постоянными или инъецированными, которые я смог найти. ИМХО, что самая большая вещь, которую он не хватает, но я думаю, что это дизайн, а не упущение.

Как отмечает Джефф Фриц, теоретически можно создать пользовательский менеджер времени жизни, который знает, какой экземпляр контекста вводить в различные типы, но уровень жесткого кодирования, который, кажется, устраняет цель использования Unity или DI в первом место.

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

Ответ 6

Другая альтернатива, которую вы могли бы использовать (не знаю, действительно ли это хорошая практика) создает два контейнера и регистрирует экземпляр для каждого:

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

надеюсь, что это тоже поможет

Ответ 7

NotDan, я думаю, вы, возможно, ответили на свой вопрос в комментариях к lassevk.

Во-первых, я бы использовал LifetimeManager для управления жизненным циклом и количеством экземпляров IDataContext, которые создает Unity.
http://msdn.microsoft.com/en-us/library/cc440953.aspx

Похоже, что объект ContainerControlledLifetimeManager предоставит вам управление экземплярами, в котором вы нуждаетесь. Используя этот LifetimeManager, Unity должен добавить тот же экземпляр IDataContext ко всем объектам, для которых требуется зависимость IDataContext.