Я использую 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
).
Foo(string name, int address) { ... }
container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
<2 цента>
Что, если позже вы решите использовать другую службу, которая требует большего или меньшего, чем просто контекст?
Проблема с параметрами конструктора и IoC заключается в том, что параметры в конечном итоге привязаны к конкретному используемому типу, а не являются частью контракта, определяемого интерфейсом службы.
Я предлагаю вам либо разрешить контекст, и я считаю, что у Unity должен быть способ избежать создания трех его экземпляров, либо вам следует подумать о фабричной службе, которая позволяет вам создать объект.
Например, что, если вы позже решите создать репозиторий, который вообще не полагается на традиционную базу данных, а вместо этого будет использовать XML-файл для создания фиктивных данных для теста? Как бы вы подали содержимое XML в этот конструктор?
IoC основан на разделении кода, привязав тип и семантику аргументов к конкретным типам, вы действительно не выполнили разделение правильно, все еще существует зависимость.
«Этот код может взаимодействовать с любым типом репозитория, если он реализует этот интерфейс… Да, и использует контекст данных».
Теперь я знаю, что другие контейнеры IoC поддерживают это, и у меня это тоже было в моей первой версии, но, на мой взгляд, это не относится к шагу разрешения.
</ 2 цента>
источник
Спасибо, ребята ... мой похож на пост "Exist". Увидеть ниже:
IUnityContainer container = new UnityContainer(); container.LoadConfiguration(); _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] { new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") });
источник
Вы можете использовать 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")));
источник
Resolve
принимает коллекциюResolverOverride
иInjectionConstructor
не является файломResolverOverride
.Самый короткий ответ: нет. В настоящее время 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.источник