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

时间:2015-10-11 12:44:58

标签: c# parameters constructor dependency-injection unity-container

我在我的项目中引入了依赖注入。我有一个对话窗口,可以作为新实体或现有实体的编辑器。它的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?

2 个答案:

答案 0 :(得分:4)

使用代码中的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视图模型的类(例如,通过构造函数注入)。

由于您使用的是DI容器,因此需要在Composition Root中使用IContractWindowViewModelFactory注册ContractWindowViewModelFactory。您还需要注册IRepository<Contract>(我猜您已经这样做了。)

现在,在您的按钮处理程序(或命令处理程序)中,您可以使用工厂为新的或现有的ContractWindowViewModel创建Contract

如果由于某种原因,你仍然想要使用按钮处理程序中的容器(我鼓励你),那么你可以像这样使用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));

答案 1 :(得分:0)

可能是这样的......

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