C#:将含未知键的JSON对象数组反序列化为泛型属性
解决Newtonsoft.Json反序列化动态键对象为泛型列表的问题
你遇到的核心痛点很明确:API返回的Settings是个带动态自定义键的对象,但你不想为100+个可能的键提前定义模型字段,而是希望转换成ColumnName+ColumnValue的泛型列表。下面给你两种实用的解决方案:
方案一:手动遍历JObject属性(快速落地)
既然你已经在用dynamic和JObject处理反序列化,最直接的方式就是手动遍历Settings的键值对,逐个生成ColumnSettingsResult实例:
修改你现有foreach循环里的代码:
foreach (var obj in innerResult) { resultList.Add( new EnumerateAccountHistoryStatisticsResult { AccountId = obj.AccountId, Flags = obj.Flags.ToObject<IEnumerable<string>>(), PartnerId = obj.PartnerId, // 把Settings对象转成目标列表 Settings = obj.Settings.Cast<JProperty>() .Select(prop => new ColumnSettingsResult { ColumnName = prop.Name, ColumnValue = prop.Value.ToString() }) .ToList() }); }
这种方式不需要改模型结构,也不用额外写转换器,适合快速调整现有代码逻辑。
方案二:自定义JsonConverter(优雅长期方案)
如果想让模型自动处理这种转换,避免每次手动遍历,可以写一个自定义的JSON转换器:
1. 实现转换器类
public class SettingsConverter : JsonConverter<List<ColumnSettingsResult>> { public override List<ColumnSettingsResult> ReadJson(JsonReader reader, Type objectType, List<ColumnSettingsResult> existingValue, bool hasExistingValue, JsonSerializer serializer) { // 读取JSON里的Settings对象 var settingsObj = JObject.Load(reader); // 把每个键值对转成ColumnSettingsResult return settingsObj.Properties() .Select(prop => new ColumnSettingsResult { ColumnName = prop.Name, ColumnValue = prop.Value.ToString() }) .ToList(); } public override void WriteJson(JsonWriter writer, List<ColumnSettingsResult> value, JsonSerializer serializer) { // 如果需要把列表序列化回原JSON格式,这里做反向转换 var settingsObj = new JObject(); foreach (var setting in value) { settingsObj.Add(setting.ColumnName, setting.ColumnValue); } settingsObj.WriteTo(writer); } public override bool CanConvert(Type objectType) { return objectType == typeof(List<ColumnSettingsResult>); } }
2. 在模型中绑定转换器
修改你的主模型,给Settings属性加上转换器特性:
public class EnumerateAccountHistoryStatisticsResult { public int AccountId { get; set; } public IEnumerable<string> Flags { get; set; } public int PartnerId { get; set; } [JsonConverter(typeof(SettingsConverter))] public List<ColumnSettingsResult> Settings { get; set; } }
3. 简化反序列化代码
现在你可以直接用ToObject自动完成转换,不用再手动处理:
foreach (var obj in innerResult) { resultList.Add(obj.ToObject<EnumerateAccountHistoryStatisticsResult>()); }
特殊情况适配:如果Settings是数组类型
如果你说的“Settings数组”是指每个元素是单个键值对的对象(比如[{"AR":"val1"}, {"AN":"val2"}]),只需要稍微调整转换逻辑:
// 手动转换方式 Settings = obj.Settings.Cast<JObject>() .Select(jObj => { var prop = jObj.Properties().First(); return new ColumnSettingsResult { ColumnName = prop.Name, ColumnValue = prop.Value.ToString() }; }) .ToList()
对应的自定义转换器也可以调整ReadJson方法来适配这种数组结构。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

