c# - 您在依赖项中寻找什么来确定它是否应该是一个注入(inject)的依赖项?

标签 c# .net dependency-injection

我很难确定何时应该注入(inject)依赖项。让我们使用我的项目中的一个简单示例:

class CompanyDetailProvider : ICompanyDetailProvider {
    private readonly FilePathProvider provider;
    public CompanyDetailProvider(FilePathProvider provider) {
        this.provider = provider;
    }

    public IEnumerable<CompanyDetail> GetCompanyDetailsForDate(DateTime date) {
        string path = this.provider.GetCompanyDetailFilePathForDate(date);
        var factory = new DataReaderFactory();
        Func<IDataReader> sourceProvider = () => factory.CreateReader(
            DataFileType.FlatFile, 
            path
        );
        var hydrator = new Hydrator<CompanyDetail>(sourceProvider);
        return hydrator;
    }
}

(不是生产质量!)

ICompanyDetailProvider负责提供 CompanyDetail 的实例s 给消费者。具体实现CompanyDetailProvider通过给 CompanyDetail 的实例补水来做到这一点来自使用 Hydrator<T> 的文件它使用反射来填充 T 的实例来自 IDataReader .清楚CompanyDetailProvider依赖于 DataReaderFactory (返回 OleDbDataReader 给定文件路径的实例)和 Hydrator .是否应该注入(inject)这些依赖项?注入(inject)是否正确 FilePathProvider ?我要检查哪些品质来决定是否应该注入(inject)它们?

最佳答案

我通过意图/机制镜头评估依赖项的使用点:这段代码是否清楚地传达了它的意图,或者我是否必须从一堆实现细节中提取它?

如果代码确实看起来像一堆实现细节,我会确定输入和输出并创建一个全新的依赖关系来表示所有如何背后的原因。然后我将复杂性插入新的依赖项,使原始代码更简单、更清晰。

当我阅读这个问题中的代码时,我清楚地看到基于日期检索文件路径,然后是一组不透明的语句,这些语句没有清楚地传达读取特定类型实体的目标某条路。我可以努力完成它,但这会打断我的步伐。

我建议你在得到路径后提高计算的后半部分的抽象级别。我将从定义一个实现代码输入/输出的依赖项开始:

public interface IEntityReader
{
    IEnumerable<T> ReadEntities<T>(string path);
}

然后,使用这个暴露意图的接口(interface)重写原始类:

public sealed class CompanyDetailProvider : ICompanyDetailProvider
{
    private readonly IFilePathProvider _filePathProvider;
    private readonly IEntityReader _entityReader;

    public CompanyDetailProvider(IFilePathProvider filePathProvider, IEntityReader entityReader)
    {
        _filePathProvider = filePathProvider;
        _entityReader = entityReader;
    }

    public IEnumerable<CompanyDetail> GetCompanyDetailsForDate(DateTime date)
    {
        var path = _filePathProvider.GetCompanyDetailsFilePathForDate(date);

        return _entityReader.ReadEntities<CompanyDetail>(path);
    }
}

现在您可以对血淋淋的细节进行沙箱处理,这些细节在孤立的情况下变得非常内聚:

public sealed class EntityReader : IEntityReader
{
    private readonly IDataReaderFactory _dataReaderFactory;

    public EntityReader(IDataReaderFactory dataReaderFactory)
    {
        _dataReaderFactory = dataReaderFactory;
    }

    public IEnumerable<T> ReadEntities<T>(string path)
    {
        Func<IDataReader> sourceProvider =
            () => _dataReaderFactory.CreateReader(DataFileType.FlatFile, path);

        return new Hydrator<T>(sourceProvider);
    }
}

如本例所示,我认为您应该将数据读取器工厂抽象出来并直接实例化水合器。区别在于 EntityReader 使用 数据读取器工厂,而它仅创建 水化器。它实际上根本不依赖于实例;相反,它用作水合器工厂。

关于c# - 您在依赖项中寻找什么来确定它是否应该是一个注入(inject)的依赖项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3685747/

相关文章:

java - 默认依赖实现,没有DI框架如何处理?

c# - 如何获取 WPF 中的内置路由事件列表

c# - 如何解析这种格式的 DateTime? "Sun May 23 22:00:00 UTC+0300 2010"

c# - 防止 Entity Framework 在数据库中创建外键

asp.net - 如何从 .aspx 页面检索查询字符串值并将其传递到 ascx 页面

dependency-injection - Ioc/DI - 为什么我必须引用应用程序入口点中的所有层/组件?

c# - 使用功能区回调意味着什么?

c# - 映射的网络驱动器,File.Exists 奇怪的行为

c# - 将秒表与异步方法一起使用

走线,连接依赖项