You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型类接口的Yield返回问题:IBasic接口类型处理困扰

解决IBasic接口实现类的CSV解析Yield返回问题

嘿,我明白你现在卡在这儿了——泛型CsvRepo<T>里要给IBasic的不同实现类(InputData1、InputData2、InputData3)用yield返回解析后的CSV记录,直接拆分字符串后不知道怎么转换成对应的具体类型对吧?我来给你分享几个实用的解决方案:

首先先把你的代码片段明确一下:

internal class CsvRepo<T> : ICsvRepo<T> where T : IBasic 
{ 
    private readonly ICsvSettings _settings; 
    public CsvRepo(ICsvSettings settings) 
    { 
        _settings = settings; 
    } 
    public IEnumerable<T> GetRecords() 
    { 
        //return from line in File.ReadLines(_settings.Path) 
        // select line.Split(...) 这里不知道怎么转换成对应的T类型
    }
}

方案一:给IBasic添加静态解析方法(推荐)

给IBasic接口定义一个静态抽象方法,让每个实现类自己负责解析逻辑,这样泛型类里就能统一调用:

首先修改IBasic接口:

public interface IBasic
{
    // 你的其他接口成员
    static abstract T ParseFromCsvLine<T>(string line) where T : IBasic, new();
}

然后让每个实现类实现这个静态方法,比如InputData1:

public class InputData1 : IBasic
{
    public string PropA { get; set; }
    public int PropB { get; set; }

    // 实现自己的CSV行解析逻辑
    public static InputData1 ParseFromCsvLine(string line)
    {
        var parts = line.Split(',');
        return new InputData1
        {
            PropA = parts[0],
            PropB = int.Parse(parts[1])
        };
    }

    // 显式实现接口的泛型方法
    static IBasic IBasic.ParseFromCsvLine<IBasic>(string line) => ParseFromCsvLine(line);
}

接下来在GetRecords里就可以用yield轻松实现延迟加载了:

public IEnumerable<T> GetRecords()
{
    foreach (var line in File.ReadLines(_settings.Path))
    {
        if (string.IsNullOrWhiteSpace(line))
            continue; // 跳过空行

        var record = T.ParseFromCsvLine<T>(line);
        yield return record;
    }
}

方案二:注入专属解析器(更符合依赖注入原则)

如果不想让实体类承担解析逻辑,可以定义一个解析器接口,为每个IBasic实现类写对应的解析器,然后注入到CsvRepo<T>中:

首先定义解析器接口:

public interface ICsvParser<T> where T : IBasic
{
    T ParseLine(string line);
}

然后为InputData1写解析器:

public class InputData1Parser : ICsvParser<InputData1>
{
    public InputData1 ParseLine(string line)
    {
        var parts = line.Split(',');
        return new InputData1
        {
            PropA = parts[0],
            PropB = int.Parse(parts[1])
        };
    }
}

修改CsvRepo<T>的构造函数注入解析器:

internal class CsvRepo<T> : ICsvRepo<T> where T : IBasic 
{ 
    private readonly ICsvSettings _settings;
    private readonly ICsvParser<T> _parser;

    public CsvRepo(ICsvSettings settings, ICsvParser<T> parser) 
    { 
        _settings = settings;
        _parser = parser;
    } 

    public IEnumerable<T> GetRecords() 
    {
        foreach (var line in File.ReadLines(_settings.Path))
        {
            if (string.IsNullOrWhiteSpace(line))
                continue;

            yield return _parser.ParseLine(line);
        }
    }
}

方案三:类型判断兜底(不推荐,仅当无法修改IBasic时使用)

如果不能修改IBasic接口,也不想加解析器,可以用类型判断来处理,但这种方式违反开闭原则,后续加新的IBasic实现类时需要修改这里的代码:

public IEnumerable<T> GetRecords()
{
    foreach (var line in File.ReadLines(_settings.Path))
    {
        if (string.IsNullOrWhiteSpace(line))
            continue;

        var parts = line.Split(',');
        T record;

        if (typeof(T) == typeof(InputData1))
        {
            record = (T)(object)new InputData1
            {
                PropA = parts[0],
                PropB = int.Parse(parts[1])
            };
        }
        else if (typeof(T) == typeof(InputData2))
        {
            // 对应InputData2的解析逻辑
            record = (T)(object)new InputData2
            {
                // 赋值你的属性
            };
        }
        else if (typeof(T) == typeof(InputData3))
        {
            // InputData3的解析逻辑
            record = (T)(object)new InputData3
            {
                // 赋值你的属性
            };
        }
        else
        {
            throw new NotSupportedException($"不支持解析类型:{typeof(T)}");
        }

        yield return record;
    }
}

总结

优先选方案一或方案二,它们都遵循开闭原则,后续新增IBasic实现类时不需要修改CsvRepo<T>的代码,扩展性更好。方案三只是临时兜底的办法,尽量少用。

内容的提问来源于stack exchange,提问作者StudentOfLifeTMistakeTResult

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:10:56