C#中如何实现含重复键的Tuple/KeyValuePair集合的类字典格式JSON序列化
适配重复键键值对集合的JSON序列化实现
为什么默认逻辑无法满足需求
- 内置序列化器对
IEnumerable<KeyValuePair<string,string>>的默认处理是将其作为数组序列化,输出类似[{"Key":"test","Value":"value1"}]的结构,并非你需要的平铺对象格式 - 无论是System.Text.Json还是Newtonsoft.Json,字典类型在序列化时遇到重复键会直接抛出参数异常,完全无法承载扁平化生成后的带重复键的集合数据
具体实现
最便捷的方式是为System.Text.Json内置序列化器自定义专用转换器,完全不需要修改你现有通过SelectMany生成扁平化集合的逻辑。
转换器核心逻辑:遍历集合内的每一组键值对,直接按JSON对象属性顺序写入,不做任何键去重,重复键按原始集合顺序追加即可。
using System.Text.Json; using System.Text.Json.Serialization; public class FlattenedKeyValueListConverter : JsonConverter<IEnumerable<KeyValuePair<string, string>>> { public override void Write(Utf8JsonWriter writer, IEnumerable<KeyValuePair<string, string>> value, JsonSerializerOptions options) { writer.WriteStartObject(); foreach (var pair in value) { writer.WriteString(pair.Key, pair.Value); } writer.WriteEndObject(); } public override IEnumerable<KeyValuePair<string, string>> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 仅需序列化场景可省略反序列化实现,按需补充即可 throw new NotImplementedException(); } }
使用方式
全局复用序列化配置后,直接传入你生成的扁平化集合即可完成序列化:
var serializeOptions = new JsonSerializerOptions { Converters = { new FlattenedKeyValueListConverter() } }; // 完全沿用你现有的集合生成逻辑,无需额外改造 var flattenedList = Values.SelectMany(a => a.Value.Select(b => new KeyValuePair<string, string>(a.Key, b))); string jsonResult = JsonSerializer.Serialize(flattenedList, serializeOptions);
最终输出完全匹配你预期的格式:
{ "test": "value1", "test": "value2", "test": "value3", "test2": "somevalue" }
补充说明
- 如果你的集合元素是
Tuple<string,string>类型,只需为转换器新增对IEnumerable<Tuple<string,string>>的支持,写入逻辑保持不变,将元组的Item1作为键、Item2作为值即可 - 如果项目使用的是Newtonsoft.Json,实现逻辑完全一致:自定义继承自
Newtonsoft.Json.JsonConverter的类,在WriteJson方法中逐次向JSON写入键值对,无需将数据放入字典触发重复键校验 - 带重复键的JSON不属于严格规范的JSON格式,部分严格校验的解析器在反向解析这类内容时,会默认用后面的同名键覆盖前面的值,这是JSON协议本身的特性,不是序列化实现的问题
内容的提问来源于stack exchange,提问作者user15124099
相关产品推荐
相关产品推荐

