如何在不通知父类泛型类型的情况下对注入的类调用泛型方法

本文关键字:情况下 注入 泛型方法 调用 泛型类型 通知 父类 | 更新日期: 2023-09-27 17:59:55

下面是注入到另一个类中的依赖项的实现。

public class CsvDataProvider : ICsvDataProvider
{
    readonly ICsvReaderFactory _factory;
    public CsvDataProvider(ICsvReaderFactory factory)
    {
        _factory = factory;
    }
    public IEnumerable<TRecord> GetData<TRecord>(string filepath) where TRecord : class
    {
        var reader = _factory.CreateCsvReader(filepath);
        return reader.GetRecords<TRecord>();
    }
}

factory创建的reader将读取CSV文件中的所有行,并将每行转换为TRecord的实例。我不拥有reader代码,也不能更改GetRecords<TRecord>()方法。

这就是我陷入困境的地方:

public class CsvDataMigrationController
{
    readonly ICsvDataProvider _provider;
    readonly ICsvDataMigration _migration;
    public CsvDataMigrationController(ICsvDataProvider provider, ICsvDataMigration migration)
    {
        _provider = provider;
        _migration = migration;
    }
    public void ProcessFile(string path)
    {
        var records = _provider.GetData<I_DONT_WANT_TO_EXPLICITLY_SAY>(path); //<-- Help!
        _migration.Migrate(records);
    }
}

其目的是向CsvDataMigrationController中注入一个数据提供程序和一个迁移过程类。控制器将调用数据提供程序来获取数据,并将数据传递到迁移类中。

  • 我不想让CsvDataMigrationController知道所涉及的数据类型
  • 我不想让CsvDataProvider知道迁移的情况
  • 我不想让CsvDataMigration知道数据来自哪里

关于我如何做到这一点,有什么建议吗?

注意:我没有包括CsvDataMigration类,因为我认为它在解释中没有用处,但如果需要,我会包括它。

如何在不通知父类泛型类型的情况下对注入的类调用泛型方法

既然不能更改GetRecords,那么最简单的方法可能是向迁移接口询问记录类型,并使用反射调用具有运行时获得的类型的通用GetData方法。类似于:

public void ProcessFile(string path)
{
    Type recordType = _migration.InputRecordType;
    var getDataMethod =
        _provider.GetType()
        .GetMethod("GetData")
        .MakeGenericMethod(recordType);
    var records = getDataMethod.Invoke(_provider, new object[] { path });
    _migration.Migrate(records);
}

通常,您将定义一个非通用的替代方案,如

public interface ICsvDataProvider
{
    IEnumerable GetData(string filepath, Type recordType) 
    IEnumerable<TRecord> GetData<TRecord>(string filepath) 
        where TRecord : class;
}

所以你可以称之为

public class CsvDataMigrationController
{
    private string targetTypeName = ...;
    public void ProcessFile(string path)
    {
        var recordType = Type.GetType(this.targetTypeName);
        var records = _provider.GetData(path, recordType);
        _migration.Migrate(records);
    }
}

通过这种方式,泛型方法只是围绕非泛型方法的一点语法糖。

使用反思(如@Cameron的回答)是另一种解决方案。在这两种情况下,您都必须在运行时知道目标类型(而不是像泛型方法所要求的那样在编译时知道)。