如何将API返回JSON的OptionSets/OptionSetsClean反序列化为字典或列表?
解决JSON反序列化中OptionSetsClean和OptionSets字段的转换问题
问题分析
API返回的JSON里,OptionSetsClean是JSON字符串格式的键值对数组,而OptionSets是由单个键值对对象组成的数组。你当前定义的GetJsonResult类无法正确将这两个字段转换为Dictionary或List类型,原因如下:
OptionSets字段:用object类型接收无法自动解析为结构化集合,实际结构是List<Dictionary<string, int>>(每个元素是仅有一个键值对的字典)。OptionSetsClean字段:它本身是字符串类型的JSON,直接声明为Dictionary<string, int>会反序列化失败,因为字符串无法直接映射为字典,需要先解析字符串再二次反序列化。
解决方案
1. 修改GetJsonResult类定义
针对两个字段的特性,调整类型并添加自动转换逻辑:
using Newtonsoft.Json; using System.Linq; // 匹配API外层结构的根类 public class RootResult { [JsonProperty("GetJsonResult")] public GetJsonResult GetJsonResult { get; set; } } public class GetJsonResult { [JsonProperty("EntityName")] public string EntityName { get; set; } [JsonProperty("FailureReason")] public string FailureReason { get; set; } [JsonProperty("Counter")] public int Counter { get; set; } [JsonProperty("MoreRecords")] public bool MoreRecords { get; set; } [JsonProperty("OptionSetName")] public string? OptionSetName { get; set; } [JsonProperty("Success")] public bool Success { get; set; } // 私有字段接收原始字符串,对外提供转换后的字典 [JsonProperty("OptionSetsClean")] private string OptionSetsCleanRaw { get; set; } public Dictionary<string, int>? OptionSetsClean { get { if (string.IsNullOrEmpty(OptionSetsCleanRaw)) return null; // 先解析字符串为单键字典数组,再合并为完整字典 var singleDictList = JsonConvert.DeserializeObject<List<Dictionary<string, int>>>(OptionSetsCleanRaw); return singleDictList?.SelectMany(d => d).ToDictionary(kv => kv.Key, kv => kv.Value); } } // 直接用List<Dictionary<string, int>>接收OptionSets数组 [JsonProperty("OptionSets")] public List<Dictionary<string, int>>? OptionSets { get; set; } // 可选:提供合并后的字典属性,方便直接使用OptionSets的数据 public Dictionary<string, int>? MergedOptionSets { get => OptionSets?.SelectMany(d => d).ToDictionary(kv => kv.Key, kv => kv.Value); } [JsonProperty("Entities")] public object? Entities { get; set; } }
2. 反序列化代码示例
直接调用JsonConvert.DeserializeObject即可,类内部已处理转换逻辑:
string apiResponseJson = "你的API返回完整JSON字符串"; var rootData = JsonConvert.DeserializeObject<RootResult>(apiResponseJson); var result = rootData.GetJsonResult; // 访问转换后的字典 var cleanOptionDict = result.OptionSetsClean; var mergedOptionDict = result.MergedOptionSets;
3. 替代方案:用自定义JsonConverter处理OptionSetsClean
如果不想用私有字段+计算属性的方式,可以给OptionSetsClean添加自定义转换器:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Linq; public class StringToMergedDictConverter : JsonConverter<Dictionary<string, int>> { public override Dictionary<string, int>? ReadJson(JsonReader reader, Type objectType, Dictionary<string, int>? existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { var jsonStr = (string)reader.Value; var singleDictList = JsonConvert.DeserializeObject<List<Dictionary<string, int>>>(jsonStr); return singleDictList?.SelectMany(d => d).ToDictionary(kv => kv.Key, kv => kv.Value); } return serializer.Deserialize<Dictionary<string, int>>(reader); } public override void WriteJson(JsonWriter writer, Dictionary<string, int>? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } // 序列化时转回原格式的JSON字符串 var singleDictList = value.Select(kv => new Dictionary<string, int> { { kv.Key, kv.Value } }).ToList(); writer.WriteValue(JsonConvert.SerializeObject(singleDictList)); } }
然后在类中应用转换器:
[JsonProperty("OptionSetsClean")] [JsonConverter(typeof(StringToMergedDictConverter))] public Dictionary<string, int>? OptionSetsClean { get; set; }
关键说明
OptionSets的JSON结构是多个单键值对对象的数组,必须用List<Dictionary<string, int>>接收,直接用Dictionary会反序列化失败。OptionSetsClean是嵌套的JSON字符串,必须先解析字符串得到数组,再合并为单个Dictionary,因为原字符串内容是数组格式而非单个字典。
内容的提问来源于stack exchange,提问作者GordonS
相关产品推荐
相关产品推荐

