我有一个名为ReportWorkflow<TReport>
的类,该类调用某些对象以生成特定类型的报告,该对象始终以相同的顺序调用,唯一的不同是每个对象的实际实现。
此类的构造函数如下:
public ReportWorkflow(... , IFileNameProvider<TReport> fileNameProvider)
ReportWorkflow<TReport>
使用依赖项注入构造。
在DI容器中同时注册了多个ReportWorkflow<TReport>
,例如:
services.AddSingleton<IReportWorkflow, ReportWorkflow<HrReport>();
services.AddSingleton<IReportWorkflow, ReportWorkflow<AccountingReport>();
//More ReportWorkflows registrations...
为确保为每个ReportWorkflow<TReport>
获得正确的文件名提供程序,我已将通用参数TReport
添加到接口IFileNameProvider<TReport>
中,但是此接口从不使用通用参数,并且它只是在这里“标记”并区分一个实现。
接口定义如下
public interface IFileNameProvider<TReport> {
string GetFileName();
}
一个实现只用报表类型填充通用参数,它将像以下那样注册:
services.AddSingleton<IFileNameProvider<HrReport>, HrFileNameProvider>();
services.AddSingleton<IFileNameProvider<AccountingReport>, AccountingFileNameProvider>();
这将确保我尝试解决ReportWorkflow<HrReport>
时会得到HrFileNameProvider
,而当我尝试解决ReportWorkflow<AccountingReport>
时会得到AccountingFileNameProvider
。
“类型标记” HrReport
或AccountingReport
是其他对象使用并返回的实际类,并且确实包含一些信息。
让接口使用通用参数作为一种“标记”将一个实现与另一个实现区分开来是否有意义?如果是,该模式是否有名称?
答案 0 :(得分:4)
恭喜,您可能只是重新发明了phantom types;)
尽管这是Haskell和其他静态类型的函数式编程语言中的(古怪)东西,但这里的问题还意味着它可能不是适用于C#的最多idiomatic设计。
所有这些,在我看来,这是使DI容器与设计一起工作的一种解决方法。如果使用DI容器,则值得考虑它是否确实增加了价值,或者是否值得承担责任。
考虑扔掉容器,而是依靠Pure DI。这样可以简化一切,也可以使幻像类型的使用变得多余。