依赖注入 - 将参数传递给构造类型

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));