如何将带表头的嵌套数组JSON转换为强类型C#对象?
问题:将带动态表头的JSON响应映射为强类型集合
原始JSON响应
{ "rootEntity": "function", "count": 2, "header": [ "name", "email", "function" ], "results": [ [ "12 HOURS", "test@test.com", "testing" ], [ "Example", "example@test.com", "second" ] ] }
目标强类型结构
public class EventResults { public string? RootEntity { get; set; } public int Count { get; set; } public List<Events> Events { get; set; } } public class Events { public string Name { get; set; } public string Email { get; set; } public string Function { get; set; } }
需求:不依赖表头的固定索引(比如name不一定在索引0),将上述JSON转换为目标强类型集合,且服务后续可能新增字段。
解决方案
方法1:手动映射结合反射(灵活适配字段变化)
先把JSON反序列化为中间类,再通过表头字段名与属性名的大小写不敏感匹配完成映射:
1. 定义匹配原始JSON的中间类
public class RawResponse { [JsonProperty("rootEntity")] public string? RootEntity { get; set; } [JsonProperty("count")] public int Count { get; set; } [JsonProperty("header")] public List<string> Header { get; set; } [JsonProperty("results")] public List<List<string>> Results { get; set; } }
2. 编写映射逻辑
利用反射建立属性名与表头字段名的映射,遍历结果数组完成赋值:
public static EventResults ConvertToEventResults(RawResponse rawResponse) { var eventResults = new EventResults { RootEntity = rawResponse.RootEntity, Count = rawResponse.Count, Events = new List<Events>() }; // 建立Events类属性(小写)到属性实例的映射 var propertyMap = typeof(Events) .GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToDictionary(p => p.Name.ToLower(), p => p); foreach (var resultRow in rawResponse.Results) { var evnt = new Events(); for (int i = 0; i < rawResponse.Header.Count; i++) { var headerName = rawResponse.Header[i].ToLower(); if (propertyMap.TryGetValue(headerName, out var property)) { property.SetValue(evnt, resultRow[i]); } // 新增字段若不在Events类中,可选择忽略或添加日志、额外处理 } eventResults.Events.Add(evnt); } return eventResults; }
使用示例
string json = "你的JSON响应字符串"; var rawResponse = JsonConvert.DeserializeObject<RawResponse>(json); var eventResults = ConvertToEventResults(rawResponse);
方法2:自定义JsonConverter(反序列化时自动处理)
如果希望直接将JSON反序列化为EventResults,可以自定义Newtonsoft的转换器:
public class EventResultsConverter : JsonConverter<EventResults> { public override EventResults ReadJson(JsonReader reader, Type objectType, EventResults existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var eventResults = new EventResults { RootEntity = jObject["rootEntity"]?.ToString(), Count = jObject["count"]?.Value<int>() ?? 0, Events = new List<Events>() }; var headers = jObject["header"]?.ToObject<List<string>>(); var results = jObject["results"]?.ToObject<List<List<string>>>(); if (headers == null || results == null) return eventResults; var propertyMap = typeof(Events) .GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToDictionary(p => p.Name.ToLower(), p => p); foreach (var row in results) { var evnt = new Events(); for (int i = 0; i < headers.Count; i++) { var header = headers[i].ToLower(); if (propertyMap.TryGetValue(header, out var prop)) { prop.SetValue(evnt, row[i]); } } eventResults.Events.Add(evnt); } return eventResults; } public override void WriteJson(JsonWriter writer, EventResults value, JsonSerializer serializer) { // 若需要将强类型对象序列回原始JSON格式,可在此实现逻辑 throw new NotImplementedException(); } }
使用示例
string json = "你的JSON响应字符串"; var settings = new JsonSerializerSettings(); settings.Converters.Add(new EventResultsConverter()); var eventResults = JsonConvert.DeserializeObject<EventResults>(json, settings);
说明
两种方案均通过表头字段名与属性名的大小写不敏感匹配规避固定索引依赖,后续服务新增字段时,只需在Events类中添加对应属性,映射逻辑会自动适配,无需修改转换代码。若新增字段无需映射,代码会自动忽略,也可根据需求添加日志或额外处理逻辑。
内容的提问来源于stack exchange,提问作者jmlumpkin
相关产品推荐
相关产品推荐

