2

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

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

将读取 CSV 文件中readerfactory所有行并将每一行转换为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该类,因为我认为它在解释中没有用,但如果需要,会包含它。

4

2 回答 2

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);
}
于 2013-02-19T05:59:05.500 回答
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 的回答)是另一种解决方案。在这两种情况下,您都必须在运行时知道目标类型(而不是像泛型方法所要求的那样在编译时)。

于 2013-02-19T06:00:12.500 回答