在 ClassMap ConvertUsing 方法中创建新记录

Create new record inside a ClassMap ConvertUsing method

案例是我正在解析一个文件,它看起来像这样。

Name Account
Foo client 123
Bar client 456,789

在真实数据中我做了更多的事情,清理帐户等,但重点是帐户列中的 ,。我现在得到一个有 2 条记录的 IEnumerable,我想得到一个有 3 条记录的 IEnumerable,方法是在“帐户”列中用逗号分隔记录。

像这样。

Name Account
Foo client 123
Bar client 456
Bar client 789

是否可以通过 CSV Helper 实现?

void Main()
{
    using (var sReader = new StringReader("Name,Account\nFoo client,123\nBar client,\"456,789\""))
    using (var csvReader = new CsvHelper.CsvReader(sReader, CultureInfo.InvariantCulture))
    {
        csvReader.Read();
        csvReader.ReadHeader();
        
        var records = new List<Foo>();
        
        while (csvReader.Read())
        {
            var name = csvReader.GetField("Name");
            var account = csvReader.GetField("Account");
            
            var splitAccounts = account.Split(",");
            
            foreach(var item in splitAccounts)
            {
                records.Add(new Foo { Name = name, Account = int.Parse(item)});
            }
            
        }
        records.Dump();
    }
}

public class Foo 
{
    public string Name { get; set; }
    public int Account { get; set; }
}

更新: 每一行都是一条记录,所以您真的不能用行外的 ClassMap 创建新记录。您可以做的是将您的 class 包装在另一个 class 中,其中包含您尝试创建的 List<MyClass> 个记录,然后将它们组合回单个 List<MyClass>.如果 Account 可以在 MyClass 中输入 string,你可以不用单独的 MyClassMap 就可以离开,只需让它 AutoMap() 你的 class.

void Main()
{
    using (var sReader = new StringReader("Name,Account\nFoo client,123\nBar client,\"456,789\""))
    using (var csvReader = new CsvHelper.CsvReader(sReader, CultureInfo.InvariantCulture))
    {
        csvReader.Configuration.RegisterClassMap<FooMap>();
        csvReader.Configuration.RegisterClassMap<MyClassMap>();
        
        var wrappedRecords = csvReader.GetRecords<Foo>();
        
        var records = wrappedRecords.SelectMany(r => r.Clients).ToList();
        
        records.Dump();
    }
}

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(x => x.Clients).ConvertUsing(x =>
        {
            var records = new List<MyClass>();
            
            var record = x.GetRecord<MyClass>();
            
            var splitAccounts = x.GetField("Account").Split(",");

            foreach (var item in splitAccounts)
            {
                records.Add(new MyClass { Name = record.Name, Account = int.Parse(item) });
            }
            
            return records;
        });
    }
}

public class MyClassMap : ClassMap<MyClass>
{
    public MyClassMap()
    {
        Map(x => x.Name);
    }   
}

public class Foo
{
    public List<MyClass> Clients { get; set; }
}

public class MyClass
{
    public string Name { get; set; }
    public int Account { get; set; }
}