注入需要对象取决于构造函数注入中的条件

Inject require object depends on condition in constructor injection

我有接口

public interface ITrnsitReport
{
    List<UserDefinedType> GetTransitReportData ();
}

而且它只有一种实现,即

public class TransitReport : ITrnsitReport
{
    private IValidateInput _inputValidation = null;
    private readonly ITransitRepository _transitRepo = null;
    public TransitReport (IValidateInput inputValidation,
                            ITransitRepository transitRepo)
    {
        _inputValidation = inputValidation;
        _transitRepo = transitRepo;
    }
    public List<UserDefinedType> GetTransitReportData (string input1, string input2)
    {
        List<UserDefinedType> ppdcReportList = null;
        bool isValid = _inputValidation.IsInputValid (input1, input2);
        if (isValid)
        {
            ppdcReportList = _transitRepo.GetTransitData (input1, input2);
            // do something with data
        }
        return ppdcReportList;
    }
}

现在IValidateInputPPDCValidateInputPAIValidateInput两种实现方式。再次针对 ITransitRepository,例如 PPDCTransitRepositoryPAITransitRepository。 (其中 PAI 和 PPDC 是业务报告,每个都有不同的验证和存储库)

我正在使用 Unity Framework 并让他们将它们注册到 UnityConfig.cs

我正在尝试做的新事情是

public TransitInfo : ITransitInfo
{
    private ITrnsitReport _report = null;
    public TransitInfo (ITrnsitReport report)
    {
        _report = report;
    }
    public List<UserDefinedType> GetReportData (string reportType, string input1, string input2)
    {
        if (reportType.Equals ("PAI"))
        {
            _report.GetTransitReportData (input1, input2); //inject PAIValidateInput and PAITransitRepository objects
        }
        if else (reportType.Equals ("PPDC"))
        {
            _report.GetTransitReportData (input1, input2); //inject PPDCValidateInput and PPDCTransitRepository objects
        }
    }
}

当它的 "PAI" 我如何将 PAIValidateInputPAITransitRepository 对象注入到 TransitReport 构造函数和 "PPDC" PPDCValidateInputPPDCTransitRepository 个对象。

您有多种选择,我更喜欢的一种是使用命名注册:

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC");        
container.RegisterType<IValidateInput, PAIValidateInput>("PAI");

然后您需要使用覆盖解析 ITransitInfo:

container.Resolve<ITransitInfo>(new InjectionConstructor(new ResolvedParameter<IValidateInput>("PPDC"), ...)

有几种方法。

1. 使用命名注册。

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC");

container.RegisterType<IValidateInput, PAIValidateInput>("PAI");

在你的构造函数中:

public TransitReport ([Dependency("PPDC")]IValidateInput inputValidation,
                        ITransitRepository transitRepo)
{
    _inputValidation = inputValidation;
    _transitRepo = transitRepo;
}

或在您的注册中:

container.Register<ITrnsitReport>(new InjectionConstructor(new ResolvedParameter<IValidateInput>("PPDC"));

这种方法的缺点是接口的使用者需要知道它想要接口的哪种实现,这首先打破了注入接口的整个想法。


2. 使用枚举来定义它正在验证的内容。

public interface ITrnsitReport
{
    List<UserDefinedType> GetTransitReportData ();
    ValidateType ValidateType { get; }
}

public enum ValidateType
{
    PPDC = 1,
    PAI = 2
}

然后 select 当你想用它的时候。

public TransitReport (IValidateInput[] inputValidation,
                        ITransitRepository transitRepo)
{
    _inputValidation = inputValidation.FirstOrDefault(x => x.ValidateType == ValidateType.PPC);
    _transitRepo = transitRepo;
}

好的部分是逻辑在界面本身内部,与注册无关。但是,它仍然需要接口的消费者知道它想要什么。


3.使用不同的接口。 (可能是我认为的最佳选择)

public interface IPAIValidateInput : IValidateInput
{

}

public interface IPPDCValidateInput : IValidateInput
{

}

然后在你的容器中分别注册它们,注入你真正想要的接口。

public TransitReport (IPAIValidateInput inputValidation,
                        ITransitRepository transitRepo)
{
    _inputValidation = inputValidation;
    _transitRepo = transitRepo;
}

需要没有实际声明的接口。但在我看来,它使 DI 逻辑更加纯净。


4.使用一个基数class,然后将它们全部组合起来。

首先修复命名注册:

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC");
container.RegisterType<IValidateInput, PAIValidateInput>("PAI");
container.RegisterType<ITransitRepository, PPDCTransitRepository>("PPDC");
container.RegisterType<ITransitRepository, PAITransitRepository>("PAI");
container.RegisterType<ITransitReport, PAITransitReport>("PAI");
container.RegisterType<ITransitReport, PPDCTransitReport>("PPDC");

然后创建基地class

public abstract class TransitReportBase : ITrnsitReport
{
    private readonly IValidateInput _inputValidation;
    private readonly ITransitRepository _transitRepo;

    protected TransitReportBase(IValidateInput inputValidation,
                            ITransitRepository transitRepo)
    {
        _inputValidation = inputValidation;
        _transitRepo = transitRepo;
    }

    public List<UserDefinedType> GetTransitReportData(string input1, string input2)
    {
        List<UserDefinedType> ppdcReportList = null;
        bool isValid = _inputValidation.IsInputValid(input1, input2);
        if (isValid)
        {
            ppdcReportList = _transitRepo.GetTransitData(input1, input2);
            // do something with data
        }
        return ppdcReportList;
    }
}

public class PAITransitReport : TransitReportBase
{

    public PAITransitReport([Dependency("PAI")] IValidateInput inputValidation,
                            [Dependency("PAI")] ITransitRepository transitRepo) : base(inputValidation, transitRepo)
    {

    }
}

public class PPDCTransitReport : TransitReportBase
{
    public PPDCTransitReport([Dependency("PPDC")] IValidateInput inputValidation,
                            [Dependency("PPDC")] ITransitRepository transitRepo) : base(inputValidation, transitRepo)
    {

    }
}

并使用工厂解决它们:

public class TransitReportFactory : ITransitReportFactory
{
    private readonly IUnityContainer _container;

    public TransitReportFactory(IUnityContainer container) // container is injected automatically.
    {
        _container = container;
    }

    ITrnsitReport Create(string reportType)
    {
        return _container.Resolve<ITrnsitReport>(reportType);
    }
}

感谢具体的 classes PPDCTransitReportPAITransitReport 我们可以确保将正确的依赖项注入基础 class.

工厂使用方法:

首先,用Unity注册。

container.RegisterType<ITransitReportFactory, TransitReportFactory>();

然后注入你的TransitInfo.

public TransitInfo : ITransitInfo
{
    private ITransitReportFactory _transitReportFactory;
    public TransitInfo (ITransitReportFactory transitReportFactory)
    {
        _transitReportFactory = transitReportFactory;
    }
    public List<UserDefinedType> GetReportData (string reportType, string input1, string input2)
    {
        // Create your transitreport object.
        ITransitReport report = _transitReportFactory.Create(reportType);
        var reportData = report.GetTransitReportData (input1, input2);
        return reportData;
    }
}

但我不得不说工厂本身并没有给解决方案增加那么多。如果您不介意服务定位器模式,您可以将 IUnityContainer 直接注入 TransitInfo.