如何将嵌套结构的Customer对象序列化为Dictionary<string, string>
如何将嵌套类对象转换为带点分隔键的字典?
类结构
public class Customer { public string ID { get; set; } public Address contact { get; set; } } public class Address { public string city { get; set; } }
预期输出
Dictionary<string, string> result = new Dictionary<string, string>() { { "ID", "1" }, { "contact.city", "Miami" } };
报错信息
Unhandled exception. Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: {. Path 'contact', line 1, position 21.
at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)
原代码
Customer customer = new Customer() { ID = "1", contact = new Address() { city = "Miami" } }; string customerString = Newtonsoft.Json.JsonConvert.SerializeObject(customer); Dictionary<string, string> result = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(customerString);
解决方案
直接反序列化失败的原因是:contact对应的值是嵌套JSON对象,而非字符串,无法直接映射到Dictionary<string, string>类型。可以通过递归遍历JSON结构、扁平化嵌套路径来实现需求,以下是两种可行方案:
方案一:递归扁平化JObject
直接利用JObject遍历所有属性,递归拼接嵌套路径作为字典键:
using Newtonsoft.Json.Linq; Customer customer = new Customer() { ID = "1", contact = new Address() { city = "Miami" } }; JObject jObject = JObject.FromObject(customer); Dictionary<string, string> result = new Dictionary<string, string>(); FlattenJObject(jObject, "", result); // 递归处理嵌套结构的方法 void FlattenJObject(JToken token, string prefix, Dictionary<string, string> dict) { if (token is JValue value) { dict.Add(prefix.Trim('.'), value.ToString()); return; } if (token is JObject obj) { foreach (var prop in obj.Properties()) { string newPrefix = string.IsNullOrEmpty(prefix) ? prop.Name : $"{prefix}.{prop.Name}"; FlattenJObject(prop.Value, newPrefix, dict); } } }
方案二:自定义JsonConverter
如果需要复用该逻辑,可以编写自定义转换器,统一处理扁平化逻辑:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class FlatDictionaryConverter : JsonConverter<Dictionary<string, string>> { public override Dictionary<string, string> ReadJson(JsonReader reader, Type objectType, Dictionary<string, string> existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var dict = new Dictionary<string, string>(); FlattenJObject(jObject, "", dict); return dict; } public override void WriteJson(JsonWriter writer, Dictionary<string, string> value, JsonSerializer serializer) { // 若需将扁平化字典序列化回嵌套结构,可在此实现逻辑 throw new NotImplementedException(); } private void FlattenJObject(JToken token, string prefix, Dictionary<string, string> dict) { if (token is JValue value) { dict.Add(prefix.Trim('.'), value.ToString()); return; } if (token is JObject obj) { foreach (var prop in obj.Properties()) { string newPrefix = string.IsNullOrEmpty(prefix) ? prop.Name : $"{prefix}.{prop.Name}"; FlattenJObject(prop.Value, newPrefix, dict); } } } } // 使用方式 Customer customer = new Customer() { ID = "1", contact = new Address() { city = "Miami" } }; string customerString = JsonConvert.SerializeObject(customer); var result = JsonConvert.DeserializeObject<Dictionary<string, string>>(customerString, new FlatDictionaryConverter());
两种方案都能生成你预期的带点分隔键的字典结构,核心逻辑是递归解析嵌套JSON对象,将层级路径拼接为字典键,对应值提取为字符串。
内容的提问来源于stack exchange,提问作者Impostor
相关产品推荐
相关产品推荐

