注入需求对象取决于构造函数注入中的条件 [英] Inject require object depends on condition in constructor injection

查看:76
本文介绍了注入需求对象取决于构造函数注入中的条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个界面

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

现在, IValidateInput 具有两个实现,例如 PPDCValidateInput PAIValidateInput .再次使用 ITransitRepository ,例如 PPDCTransitRepository PAITransitRepository .(其中PAI和PPDC是业务报告,并且每个都有不同的验证和存储库)

Now IValidateInput has two implementations such as PPDCValidateInput and PAIValidateInput. Again for ITransitRepository such as PPDCTransitRepository and PAITransitRepository. (where PAI and PPDC are business reports and each has different validation and repository)

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

I am using Unity Framework and have them registered them to 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"时,如何将 PAIValidateInput PAITransitRepository 对象注入到 TransitReport 构造函数中,并为"PPDC"注入 PPDCValidateInput PPDCTransitRepository 对象.

When its "PAI" how can I inject PAIValidateInput and PAITransitRepository objects to TransitReport constructor and for "PPDC" PPDCValidateInput and PPDCTransitRepository objects.

推荐答案

有几种方法.

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

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

The downside with this approach is that the consumer of the interface needs to know which implementation of the interface it wants, which kind of breaks the whole idéa of injecting an interface in the first place.

2..使用枚举定义要验证的内容.

2. Use an Enum to define what it's validating.

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

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

然后在要使用它时选择它.

And then select it when you want to use it.

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

好的地方是逻辑位于接口本身内部,而不涉及注册.但是,它仍然需要接口的使用者知道它想要什么.

The good part is that the logic is inside the interface itself, and not regarding the registration. However, it still requires the consumer of the interface to know what it wants.

3..使用不同的界面.(可能是我认为最好的选择)

3. Use different interfaces. (Probably the best option in my oppinion)

public interface IPAIValidateInput : IValidateInput
{

}

public interface IPPDCValidateInput : IValidateInput
{

}

然后将它们分别注册到您的容器中,并注入您真正想要的接口.

And then register them separately in your container and inject the interface you actually want.

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

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

Requires interfaces without no actual declaration. But it keeps the DI-logic more pure, in my oppinion.

4..使用基类并将它们全部结合起来.

4. Use a base class and combine them all.

第一个修复的命名注册:

First fix named registrations:

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

然后创建一个基类

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

    }
}

并使用工厂来解决它们:

And use a Factory to resolve them:

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

感谢具体类 PPDCTransitReport PAITransitReport ,我们可以确保将正确的依赖项注入到基类中.

Thanks to the concrete classes PPDCTransitReport and PAITransitReport we can make sure that the right dependency is injected to the base class.

如何使用工厂:

首先,在Unity中注册它.

First, register it with 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 .

But I have to say that the factory itself doesn't add that much to the solution. If you don't mind the service locator-pattern you can inject IUnityContainer directly to TransitInfo.

这篇关于注入需求对象取决于构造函数注入中的条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆