我有一个界面
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是业务报告,每个都有不同的验证和存储库)
我正在使用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”时,如何将PAIValidateInput
和PAITransitRepository
个对象注入TransitReport
构造函数以及“PPDC”PPDCValidateInput
和PPDCTransitRepository
个对象。< / p>
答案 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);
}
}
由于具体类PPDCTransitReport
和PAITransitReport
,我们可以确保将正确的依赖项注入基类。
如何使用工厂:
首先,将它注册到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"), ...)