使用通用参数选择将注入哪个服务实现是否有意义?

时间:2018-08-22 10:30:13

标签: c# oop design-patterns dependency-injection inversion-of-control

我有一个名为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

“类型标记” HrReportAccountingReport是其他对象使用并返回的实际类,并且确实包含一些信息。

让接口使用通用参数作为一种“标记”将一个实现与另一个实现区分开来是否有意义?如果是,该模式是否有名称?

1 个答案:

答案 0 :(得分:4)

恭喜,您可能只是重新发明了phantom types;)

尽管这是Haskell和其他静态类型的函数式编程语言中的(古怪)东西,但这里的问题还意味着它可能不是适用于C#的最多idiomatic设计。

所有这些,在我看来,这是使DI容器与设计一起工作的一种解决方法。如果使用DI容器,则值得考虑它是否确实增加了价值,或者是否值得承担责任。

考虑扔掉容器,而是依靠Pure DI。这样可以简化一切,也可以使幻像类型的使用变得多余。