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

时间:2013-02-19 05:48:03

标签: c# .net generics interface dependency-injection

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

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>();
    }
}

reader创建的factory将读取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类,因为我认为它在解释中没有用,但如果需要则会包含它。

2 个答案:

答案 0 :(得分:3)

好吧,既然你不能改变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);
}

答案 1 :(得分:3)

通常,您将定义非通用替代方案,例如

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的回答)是另一种解决方案。在这两种情况下,您必须在运行时知道目标类型(而不是在通用方法要求的编译时)。