使用CSVHelper时如何无需创建ClassMap即可将CSV行号映射到POCO?
解决方案
以下两种方案都不需要修改现有POCO的IndexAttribute映射逻辑,也不需要为每个POCO单独编写ClassMap:
方案1:自定义属性+通用映射注册(符合属性映射需求)
你可以自己实现一个行号标记属性,配合全局自动注册映射逻辑完成行号注入,全程不用修改原有业务代码:
- 定义行号标记属性
[AttributeUsage(AttributeTargets.Property)] public class CsvRowNumberAttribute : Attribute { }
- 给你的POCO基类属性加上该标记
public abstract class CsvPocoBase { [CsvRowNumber] public int RowNumber { get; set; } }
- 全局注册通用映射,只需在初始化CSV配置时执行一次
using CsvHelper; using CsvHelper.Configuration; using System.Reflection; using System.Globalization; // 初始化CSV配置 var csvConfig = new CsvConfiguration(CultureInfo.InvariantCulture); // 自动扫描所有POCO生成映射 var allPocoTypes = Assembly.GetExecutingAssembly() .GetTypes() .Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(CsvPocoBase))); foreach (var pocoType in allPocoTypes) { // 生成默认ClassMap,会自动读取现有IndexAttribute配置 var genericMapType = typeof(DefaultClassMap<>).MakeGenericType(pocoType); var classMap = (ClassMap)Activator.CreateInstance(genericMapType); // 找到打了CsvRowNumberAttribute的属性,映射行号 var rowNumberProp = pocoType.GetProperties() .FirstOrDefault(p => p.GetCustomAttribute<CsvRowNumberAttribute>() != null); if (rowNumberProp != null) { classMap.Map(pocoType, rowNumberProp.Name) .Convert(args => args.Row.Context.Row); } // 注册映射到配置 csvConfig.RegisterClassMap(classMap); }
后续你新增任何继承该基类的POCO,都会自动支持行号注入,不需要额外操作。
方案2:读取时手动赋值(最轻量,无需修改映射逻辑)
如果不想做全局注册,直接在读取记录时多加一行赋值即可:
using var reader = new StreamReader("你的CSV文件路径"); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); var resultList = new List<你的POCO类型>(); while (csv.Read()) { var record = csv.GetRecord<你的POCO类型>(); // 手动赋值行号 record.RowNumber = csv.Context.Row; resultList.Add(record); }
该方案完全不涉及现有映射逻辑的修改,适合临时少量使用的场景。
内容的提问来源于stack exchange,提问作者Ian Kemp - SO dead by AI greed
相关产品推荐
相关产品推荐

