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

时间:2016-05-12 10:30:44

标签: c# unity-container solid-principles

我有一个界面

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有两个实现,例如PPDCValidateInputPAIValidateInput。同样适用于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个对象。< / p>

2 个答案:

答案 0 :(得分:3)

有几种方法可以去。

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
}

然后在您想要使用它时选择它。

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. 使用基类并将它们全部合并。

首先修复命名注册:

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

    }
}

使用工厂解决它们:

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

由于具体类PPDCTransitReportPAITransitReport,我们可以确保将正确的依赖项注入基类。

如何使用工厂:

首先,将它注册到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

答案 1 :(得分:0)

您有几种选择,我更喜欢使用命名注册:

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

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

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