C#使用CsvHelper调用WriteRecord抛出IEnumerable无法自动映射异常如何解决
报错原因
第一个ConfigurationException异常
你错误使用了WriteRecord方法:CsvHelper的WriteRecord接收的是要序列化的实体对象,而你提前将PayRecord手动拼接为string类型的逗号分隔串传入。string实现了IEnumerable<char>接口,CsvHelper会将其识别为集合类型而非单条记录,因此抛出无法自动映射IEnumerable类型的异常。
第二个ArgumentNullException异常
你的PayRecord类没有无参公共构造函数,CsvHelper自动映射带参构造的参数时触发了空引用异常。同时你还存在一个隐藏问题:写入表头后没有调用NextRecord()换行,会导致表头和第一条数据挤在同一行。
修复方案
最简修复代码
不需要手动拼接CSV行,CsvHelper会自动处理字段序列化、特殊字符转义、分隔符生成等逻辑:
using System.Globalization; using CsvHelper; public static void Write(string file, List<PayRecord> payrecords) { using (StreamWriter sw = new StreamWriter(file)) using (CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture)) { cw.WriteHeader<PayRecord>(); // 写入表头后必须换行 cw.NextRecord(); // 直接批量写入整个集合即可,无需手动循环 cw.WriteRecords(payrecords); } }
表头与属性名不匹配的适配
如果你的PayRecord属性名和需要输出的表头不一致(比如原代码表头EmployeeId对应类属性Id),需要自定义映射规则:
- 定义映射类
using CsvHelper.Configuration; public sealed class PayRecordMap : ClassMap<PayRecord> { public PayRecordMap() { // 属性Id对应表头EmployeeId Map(p => p.Id).Name("EmployeeId"); Map(p => p.Gross).Name("Gross"); Map(p => p.Tax).Name("Tax"); Map(p => p.Net).Name("Net"); } }
- 写入前注册映射
public static void Write(string file, List<PayRecord> payrecords) { using (StreamWriter sw = new StreamWriter(file)) using (CsvWriter cw = new CsvWriter(sw, CultureInfo.CurrentCulture)) { // 注册自定义映射 cw.Context.RegisterClassMap<PayRecordMap>(); cw.WriteHeader<PayRecord>(); cw.NextRecord(); cw.WriteRecords(payrecords); } }
额外注意项
- 如果
PayRecord没有无参构造函数,要么为它添加一个公共无参构造,要么在ClassMap中明确指定构造函数的映射规则即可解决第二个空引用异常。 - 如果确实需要单条循环写入,将
WriteRecord的入参改为PayRecord实体即可,示例:
cw.WriteHeader<PayRecord>(); cw.NextRecord(); foreach (var record in payrecords) { cw.WriteRecord(record); cw.NextRecord(); }
内容的提问来源于stack exchange,提问作者JUJU
相关产品推荐
相关产品推荐

