使用CSVHelper序列化/反序列化Dictionary<TKey,TValue>遇异常求助
问题背景
我需要用CSVHelper读写Dictionary<int, Sequence>类型的CSV文件,但尝试后抛出了MissingMethodException异常,相关代码和异常信息如下:
写入代码片段
using var writer = new StreamWriter(_filePath); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); if (_classMap != null) { csv.Context.RegisterClassMap(_classMap); } csv.WriteHeader(typeof(Dictionary<TKey, TValue>)); csv.NextRecord(); foreach (var value in _store) { csv.WriteRecord(new KeyValuePair<TKey,TValue>(value.Key,value.Value)); csv.NextRecord(); }
读取代码片段
using var reader = new StreamReader(_filePath); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); _ = csv.Read(); _ = csv.ReadHeader(); if (_classMap != null) { csv.Context.RegisterClassMap(_classMap); } while (csv.Read()) { var key = csv.GetField<TKey>(0); var value = csv.GetRecord<TValue>(); _store[key] = value; }
Sequence类定义
public class Sequence { public int SequenceId { get; set; } public int NextId { get; set; } }
抛出的异常
System.MissingMethodException: Constructor 'CsvHelper.Configuration.DefaultClassMap
1[[System.Collections.Generic.KeyValuePair2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e09],[FourDBS.SmartMeter.Common.Managers.Sequence, Four.DBS.Meadow.SmartMeter.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]()'
解决方案
这个异常是因为CSVHelper尝试为KeyValuePair<TKey,TValue>创建默认类映射,但KeyValuePair是结构体,没有无参构造函数,导致映射创建失败。可以通过以下两种方式修复:
方式一:手动读写字段(简单直接)
修复写入逻辑
不需要依赖自动映射,手动定义表头并写入每个字段:
using var writer = new StreamWriter(_filePath); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); // 写入自定义表头 csv.WriteField("Key"); csv.WriteField(nameof(Sequence.SequenceId)); csv.WriteField(nameof(Sequence.NextId)); csv.NextRecord(); // 遍历Dictionary写入每一行 foreach (var kvp in _store) { csv.WriteField(kvp.Key); csv.WriteField(kvp.Value.SequenceId); csv.WriteField(kvp.Value.NextId); csv.NextRecord(); }
修复读取逻辑
对应写入格式,手动读取字段并构造对象:
using var reader = new StreamReader(_filePath); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); csv.Read(); csv.ReadHeader(); while (csv.Read()) { var key = csv.GetField<int>("Key"); var sequence = new Sequence { SequenceId = csv.GetField<int>(nameof(Sequence.SequenceId)), NextId = csv.GetField<int>(nameof(Sequence.NextId)) }; _store[key] = sequence; }
方式二:自定义类映射(可复用)
为KeyValuePair<int, Sequence>创建自定义映射,明确指定每个字段的对应关系:
public class KeyValueSequenceMap : ClassMap<KeyValuePair<int, Sequence>> { public KeyValueSequenceMap() { Map(m => m.Key).Name("Key"); Map(m => m.Value.SequenceId).Name(nameof(Sequence.SequenceId)); Map(m => m.Value.NextId).Name(nameof(Sequence.NextId)); } }
修复写入逻辑
注册自定义映射后直接写入键值对:
using var writer = new StreamWriter(_filePath); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); csv.Context.RegisterClassMap<KeyValueSequenceMap>(); csv.WriteHeader<KeyValuePair<int, Sequence>>(); csv.NextRecord(); foreach (var kvp in _store) { csv.WriteRecord(kvp); csv.NextRecord(); }
修复读取逻辑
注册相同的映射后读取成键值对:
using var reader = new StreamReader(_filePath); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); csv.Context.RegisterClassMap<KeyValueSequenceMap>(); csv.Read(); csv.ReadHeader(); while (csv.Read()) { var kvp = csv.GetRecord<KeyValuePair<int, Sequence>>(); _store[kvp.Key] = kvp.Value; }
核心原因
CSVHelper的默认类映射要求目标类型具备无参构造函数,但KeyValuePair<TKey,TValue>是结构体,仅提供带参构造函数,无法自动生成默认映射,因此抛出MissingMethodException。通过手动读写或自定义映射即可解决该问题。
内容的提问来源于stack exchange,提问作者John Kattenhorn

