Могу ли я передать параметры конструктора методу 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).

7 ответов

Решение

На сегодняшний день они добавили эту функциональность:

Это в последней капле здесь:

http://unity.codeplex.com/SourceControl/changeset/view/33899

Обсуждение этого здесь:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

Пример:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"

< 2 цента>

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

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

Я бы посоветовал вам либо разрешить контекст, и я считаю, что в Unity должен быть способ избежать создания 3-х его экземпляров, или вы должны рассмотреть фабричный сервис, у которого есть способ создать объект.

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

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

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

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

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

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

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

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

В вашем случае этот Объект должен быть зарегистрирован под Именем, и для того же страхового случая вам необходим 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")));

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам