.NET Framework 4.8下如何将JSON对象数组反序列化为属性对象?
问题描述
我正在处理API返回的JSON字符串,结构如下:
{ "points": [ { "name": "title", "value": "Test" }, { "name": "category", "value": null }, { "name": "created", "value": 1550743894373 }, { "name": "version", "value": 1 } ] }
该JSON结构固定,根节点points包含一组或多组name-value键值对。
我原本使用以下类结构解析:
// 不能用record,必须用class,因为我只能用.NET Framework 4.8 public class Point { [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("value")] public object Value { get; set; } } public class MyViews { [JsonPropertyName("points")] public List<Point> Points { get; set; } }
对应的RestSharp请求代码:
using RestSharp; // 创建API请求 var request = new RestRequest("my-views"); // 获取API响应并反序列化为MyViews对象 var response = await client.ExecuteGetAsync<MyViews>(request); // 示例:从对象中获取数据 Point response_point = response.Data.Points.First(); // 获取第一个对象 string title; // 判断是否是title字段 if (response_point.Name == "title") { title = response_point.Value.ToString(); // 获取title的值 } // 我的目标是: // Point response_point = response.Data; // title = response_point.title;
我的反序列化目标是将数据填充到如下类结构中:
public class Point { public string title { get; set; } public string category { get; set; } public DateTime? created { get; set; } public int? version { get; set; } }
即得到一个包含所有name-value对应属性的单个Point对象,无需MyViews类中的List集合。
请问是否可以在反序列化过程中完成这个转换,或在反序列化后触发方法实现转换?我当前使用RestSharp及默认的System.Text.Json序列化器,但可自由选择序列化库,唯一限制是必须使用.NET Framework 4.8。
解决方案
方法一:使用Newtonsoft.Json自定义转换器(推荐,.NET Framework 4.8兼容性更佳)
Newtonsoft.Json(Json.NET)在.NET Framework生态中成熟稳定,自定义转换器实现灵活。
- 安装Newtonsoft.Json NuGet包:
Install-Package Newtonsoft.Json
- 实现自定义JsonConverter:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; public class PointConverter : JsonConverter<Point> { public override Point ReadJson(JsonReader reader, Type objectType, Point existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var pointsArray = jsonObject["points"] as JArray; var point = new Point(); foreach (var item in pointsArray) { var name = item["name"].ToString(); var value = item["value"]; switch (name) { case "title": point.title = value?.ToString(); break; case "category": point.category = value?.ToString(); break; case "created": if (value != null && value.Type != JTokenType.Null) { // 将毫秒时间戳转换为DateTime point.created = DateTimeOffset.FromUnixTimeMilliseconds(value.Value<long>()).DateTime; } break; case "version": if (value != null && value.Type != JTokenType.Null) { point.version = value.Value<int>(); } break; } } return point; } public override void WriteJson(JsonWriter writer, Point value, JsonSerializer serializer) { // 若无需将Point对象序列回原格式,可留空或按需实现 throw new NotImplementedException(); } }
- 配置RestSharp使用Newtonsoft.Json并添加转换器:
using RestSharp; using RestSharp.Serializers.NewtonsoftJson; // 初始化RestClient时指定NewtonsoftJson序列化器 var client = new RestClient("你的API基础地址") { UseNewtonsoftJson() }; var request = new RestRequest("my-views"); // 执行请求时注入自定义转换器 var response = await client.ExecuteGetAsync<Point>(request, ct => { ct.JsonSerializerSettings.Converters.Add(new PointConverter()); }); // 直接使用转换后的对象 var myPoint = response.Data; string title = myPoint.title; DateTime? created = myPoint.created;
方法二:使用System.Text.Json自定义转换器
若坚持使用System.Text.Json,需先安装兼容.NET Framework 4.8的NuGet包:
Install-Package System.Text.Json
- 实现自定义JsonConverter:
using System; using System.Text.Json; using System.Text.Json.Serialization; public class PointSystemTextJsonConverter : JsonConverter<Point> { public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using (var doc = JsonDocument.ParseValue(ref reader)) { var root = doc.RootElement; var points = root.GetProperty("points"); var point = new Point(); foreach (var item in points.EnumerateArray()) { var name = item.GetProperty("name").GetString(); if (item.TryGetProperty("value", out var value)) { switch (name) { case "title": point.title = value.GetString(); break; case "category": point.category = value.GetString(); break; case "created": if (!value.ValueKind.Equals(JsonValueKind.Null)) { long timestamp = value.GetInt64(); point.created = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime; } break; case "version": if (!value.ValueKind.Equals(JsonValueKind.Null)) { point.version = value.GetInt32(); } break; } } } return point; } } public override void Write(Utf8JsonWriter writer, Point value, JsonSerializerOptions options) { throw new NotImplementedException(); } }
- 配置RestSharp使用System.Text.Json并添加转换器:
using RestSharp; using RestSharp.Serializers.SystemTextJson; var jsonOptions = new JsonSerializerOptions(); jsonOptions.Converters.Add(new PointSystemTextJsonConverter()); var client = new RestClient("你的API基础地址") { UseSystemTextJson(jsonOptions) }; var request = new RestRequest("my-views"); var response = await client.ExecuteGetAsync<Point>(request); var myPoint = response.Data; // 直接访问属性 Console.WriteLine(myPoint.title);
方法三:反序列化后手动转换(简单直接)
若不想编写自定义转换器,可先反序列化为原MyViews对象,再手动映射到目标Point类:
// 先反序列化为原MyViews结构 var response = await client.ExecuteGetAsync<MyViews>(request); var myViews = response.Data; // 手动映射到目标Point类 var targetPoint = new Point(); foreach (var item in myViews.Points) { switch (item.Name) { case "title": targetPoint.title = item.Value?.ToString(); break; case "category": targetPoint.category = item.Value?.ToString(); break; case "created": if (item.Value is long timestamp) { targetPoint.created = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime; } break; case "version": if (item.Value is int version) { targetPoint.version = version; } break; } } // 直接使用转换后的对象 string title = targetPoint.title;
内容的提问来源于stack exchange,提问作者b166er
相关产品推荐
相关产品推荐

