Могу ли я передать параметры конструктора в метод Unity Resolve ()?
Я использую единство Microsoft для инъекции зависимостей, и я хочу сделать что-то вроде этого:
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 } });"
Что делать, если вы позже решите использовать другую службу, которая требует больше или меньше, чем просто контекст?
проблема с параметрами конструктора и IoC заключается в том, что параметры в конечном итоге привязаны к конкретному используемому типу, а не являются частью контракта, который определяет интерфейс службы.
мое предложение состояло бы в том, чтобы вы либо разрешили контекст, а также, и я считаю, что Unity должен иметь способ для вас избегайте создания 3 экземпляров этого, или вы должны рассмотреть заводскую службу, которая имеет способ для вас построить объект.
например, что делать, если вы позже решите построить репозиторий, который вообще не полагается на традиционную базу данных, а вместо этого использует XML-файл для создания фиктивных данных для теста? Как бы вы поступили с подачей XML-контента в этот конструктор?
МОК основан вокруг кода развязки, связывая в типе и семантике аргументы для конкретных типов, вы действительно не сделали развязку правильно, есть еще зависимость.
" этот код может работать с любым типом репозитория, если он реализует этот интерфейс.... О, и использует контекст данных".
теперь я знаю, что другие контейнеры IoC поддерживают это, и у меня это было в моей первой версии моего собственного, но, на мой взгляд, это не относится к шагу разрешения.
вы можете использовать InjectionConstructor / InjectionProperty / InjectionMethod в зависимости от вашей архитектуры инъекции в ResolvedParameter("name"), чтобы получить экземпляр предварительно зарегистрированного объекта в контейнере.
в вашем случае этот объект должен быть зарегистрирован с именем, и для того же insance вам нужен 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")));
Спасибо, ребята ... мой похож на пост по "Exist". Смотрите ниже:
IUnityContainer container = new UnityContainer(); container.LoadConfiguration(); _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] { new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") });
очень короткий ответ: нет. 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 на месте, единства следует добавить один и тот же экземпляр IDataContext для всех объектов, требующих зависимости IDataContext.
Comments