依赖注入 - 将参数传递给构造类型
Dependency Injection - passing parameters to constructed types
我正在为我的项目引入依赖注入。我有一个对话框 window,它充当新实体或现有实体的编辑器。它的 ViewModel 如下所示:
public class ContractWindowViewModel
{
private IRepository<Contract> contractRepository;
private Contract model;
private bool isNew;
public ContractWindowViewModel(Contract contract, IRepository<Contract> contractRepository)
{
if (contract == null)
throw new ArgumentNullException(nameof(contract));
if (contractRepository == null)
throw new ArgumentNullException(nameof(contractRepository));
this.contractRepository = contractRepository;
this.model = contract;
this.isNew = false;
}
public ContractWindowViewModel(IRepository<Contract> contractRepository)
{
this.contractRepository = contractRepository;
this.model = new Contract();
this.isNew = true;
}
// (...)
}
计划注入IRepository<Contract>
。但有时我需要将 Contract
传递给 ViewModel(如果我想编辑现有的)或不传递(如果我想创建新的)。我应该如何使用 Unity 做到这一点?
可能是这样的...
unityContainer.Resolve<ContractWindowViewModel>(
new ResolverOverride[] {
new ParameterOverride("contract", new Contract()),
new ParameterOverride("contractRepository", new Repository<Contract>())
});
来源
http://mikaelkoskinen.net/post/unity-passing-constructor-parameters-to-resolve
使用代码中的 DI 容器(例如在按钮事件处理程序中)称为服务位置,is considered to be an anti-pattern。
您应该拥有一个允许您从按钮处理程序(或您的 ViewModel 命令)内部创建视图模型的工厂。
这里有一个工厂的例子:
public interface IContractWindowViewModelFactory
{
ContractWindowViewModel CreateForNewContract();
ContractWindowViewModel CreateForExistingContract(Contract existing_contract);
}
public class ContractWindowViewModelFactory : IContractWindowViewModelFactory
{
private readonly IRepository<Contract> m_Repository;
public ContractWindowViewModelFactory(IRepository<Contract> repository)
{
m_Repository = repository;
}
public ContractWindowViewModel CreateForNewContract()
{
return new ContractWindowViewModel(m_Repository);
}
public ContractWindowViewModel CreateForExistingContract(Contract existing_contract)
{
return new ContractWindowViewModel(existing_contract, m_Repository);
}
}
现在您需要将 IContractWindowViewModelFactory
注入到需要能够创建 ContractWindowViewModel
视图模型的 class 中(例如通过构造函数注入)。
由于您使用的是 DI 容器,因此您需要在 Composition Root 中用 ContractWindowViewModelFactory
注册 IContractWindowViewModelFactory
。您还需要注册 IRepository<Contract>
(我猜您已经完成了)。
现在,在您的按钮处理程序(或命令处理程序)中,您可以使用工厂为新的或现有的 Contract
.
创建 ContractWindowViewModel
如果出于某种原因,您仍想使用按钮处理程序中的容器(我鼓励您不要这样做),那么您可以使用named registrations像这样:
在你的作文根目录中:
container.RegisterType<ContractWindowViewModel>(
"ForNew",
new InjectionConstructor(
new ResolvedParameter<IRepository<Contract>>()));
container.RegisterType<ContractWindowViewModel>(
"ForExisting",
new InjectionConstructor(
new ResolvedParameter<Contract>(),
new ResolvedParameter<IRepository<Contract>>()));
在您的处理程序中,您可以将其用于新合同:
var viewmodel_for_new = container.Resolve<ContractWindowViewModel>("ForNew");
或现有合同:
Contract existing_contract = ...
var viewmodel_for_existing = container.Resolve<ContractWindowViewModel>(
"ForExisting",
new ParameterOverride("contract", existing_contract));
我正在为我的项目引入依赖注入。我有一个对话框 window,它充当新实体或现有实体的编辑器。它的 ViewModel 如下所示:
public class ContractWindowViewModel
{
private IRepository<Contract> contractRepository;
private Contract model;
private bool isNew;
public ContractWindowViewModel(Contract contract, IRepository<Contract> contractRepository)
{
if (contract == null)
throw new ArgumentNullException(nameof(contract));
if (contractRepository == null)
throw new ArgumentNullException(nameof(contractRepository));
this.contractRepository = contractRepository;
this.model = contract;
this.isNew = false;
}
public ContractWindowViewModel(IRepository<Contract> contractRepository)
{
this.contractRepository = contractRepository;
this.model = new Contract();
this.isNew = true;
}
// (...)
}
计划注入IRepository<Contract>
。但有时我需要将 Contract
传递给 ViewModel(如果我想编辑现有的)或不传递(如果我想创建新的)。我应该如何使用 Unity 做到这一点?
可能是这样的...
unityContainer.Resolve<ContractWindowViewModel>(
new ResolverOverride[] {
new ParameterOverride("contract", new Contract()),
new ParameterOverride("contractRepository", new Repository<Contract>())
});
来源 http://mikaelkoskinen.net/post/unity-passing-constructor-parameters-to-resolve
使用代码中的 DI 容器(例如在按钮事件处理程序中)称为服务位置,is considered to be an anti-pattern。
您应该拥有一个允许您从按钮处理程序(或您的 ViewModel 命令)内部创建视图模型的工厂。
这里有一个工厂的例子:
public interface IContractWindowViewModelFactory
{
ContractWindowViewModel CreateForNewContract();
ContractWindowViewModel CreateForExistingContract(Contract existing_contract);
}
public class ContractWindowViewModelFactory : IContractWindowViewModelFactory
{
private readonly IRepository<Contract> m_Repository;
public ContractWindowViewModelFactory(IRepository<Contract> repository)
{
m_Repository = repository;
}
public ContractWindowViewModel CreateForNewContract()
{
return new ContractWindowViewModel(m_Repository);
}
public ContractWindowViewModel CreateForExistingContract(Contract existing_contract)
{
return new ContractWindowViewModel(existing_contract, m_Repository);
}
}
现在您需要将 IContractWindowViewModelFactory
注入到需要能够创建 ContractWindowViewModel
视图模型的 class 中(例如通过构造函数注入)。
由于您使用的是 DI 容器,因此您需要在 Composition Root 中用 ContractWindowViewModelFactory
注册 IContractWindowViewModelFactory
。您还需要注册 IRepository<Contract>
(我猜您已经完成了)。
现在,在您的按钮处理程序(或命令处理程序)中,您可以使用工厂为新的或现有的 Contract
.
ContractWindowViewModel
如果出于某种原因,您仍想使用按钮处理程序中的容器(我鼓励您不要这样做),那么您可以使用named registrations像这样:
在你的作文根目录中:
container.RegisterType<ContractWindowViewModel>(
"ForNew",
new InjectionConstructor(
new ResolvedParameter<IRepository<Contract>>()));
container.RegisterType<ContractWindowViewModel>(
"ForExisting",
new InjectionConstructor(
new ResolvedParameter<Contract>(),
new ResolvedParameter<IRepository<Contract>>()));
在您的处理程序中,您可以将其用于新合同:
var viewmodel_for_new = container.Resolve<ContractWindowViewModel>("ForNew");
或现有合同:
Contract existing_contract = ...
var viewmodel_for_existing = container.Resolve<ContractWindowViewModel>(
"ForExisting",
new ParameterOverride("contract", existing_contract));