基于Newtonsoft的JSON重构与C#类反序列化方案咨询
带编号键的JSON反序列化为C#自定义类的最优实现
问题描述
需要将带编号键的JSON反序列化为自定义C#类,不想使用字符串替换这类不够优雅的方法,希望通过Newtonsoft.Json(Json.NET)将原JSON重构为指定格式以匹配自定义类,同时咨询方案可行性及更优思路,也接受其他工具包建议。
原JSON结构
{ "Meta Data": { "1. Information": "Daily Prices (open, high, low, close) and Volumes", "2. Symbol": "NVDA", "3. Last Refreshed": "2024-12-06", "4. Output Size": "Full size", "5. Time Zone": "US/Eastern" }, "Time Series (Daily)": { "2024-12-06": { "1. open": "144.6000", "2. high": "145.7000", "3. low": "141.3100", "4. close": "142.4400", "5. volume": "188505573" }, "2024-12-05": { "1. open": "145.1100", "2. high": "146.5400", "3. low": "143.9500", "4. close": "145.0600", "5. volume": "172621180" } } }
目标JSON结构(修正后,原结构存在重复键语法问题)
{ "MetaData": { "Information": "Daily Prices (open, high, low, close) and Volumes", "Symbol": "NVDA", "LastRefreshed": "2024-12-06", "OutputSize": "Full size", "TimeZone": "US/Eastern" }, "TimeSeries": { "Data": [ { "open": "144.6000", "high": "145.7000", "low": "141.3100", "close": "142.4400", "volume": "188505573", "date": "2024-12-06", "series": "Daily" }, { "open": "145.1100", "high": "146.5400", "low": "143.9500", "close": "145.0600", "volume": "172621180", "date": "2024-12-05", "series": "Daily" } ] } }
自定义C#类(修正后)
public class Data { [JsonProperty("open")] public string open { get; set; } [JsonProperty("high")] public string high { get; set; } [JsonProperty("low")] public string low { get; set; } [JsonProperty("close")] public string close { get; set; } [JsonProperty("volume")] public string volume { get; set; } [JsonProperty("date")] public string date { get; set; } [JsonProperty("series")] public string series { get; set; } } public class Root { [JsonProperty("MetaData")] public MetaData MetaData { get; set; } [JsonProperty("TimeSeries")] public TimeSeries TimeSeries { get; set; } } public class TimeSeries { [JsonProperty("Data")] public List<Data> Data { get; set; } = new List<Data>(); } public class MetaData { [JsonProperty("Information")] public string Information { get; set; } [JsonProperty("Symbol")] public string Symbol { get; set; } [JsonProperty("LastRefreshed")] public string LastRefreshed { get; set; } [JsonProperty("OutputSize")] public string OutputSize { get; set; } [JsonProperty("TimeZone")] public string TimeZone { get; set; } }
最优实现方案
方案一:手动映射(简洁高效,推荐)
直接将原JSON解析为JObject,手动提取值并映射到目标类,无需复杂配置,可读性强:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; // 原JSON字符串 var rawJson = "你的原JSON内容"; var jObject = JObject.Parse(rawJson); // 映射MetaData var metaData = new MetaData { Information = jObject["Meta Data"]["1. Information"]?.ToString(), Symbol = jObject["Meta Data"]["2. Symbol"]?.ToString(), LastRefreshed = jObject["Meta Data"]["3. Last Refreshed"]?.ToString(), OutputSize = jObject["Meta Data"]["4. Output Size"]?.ToString(), TimeZone = jObject["Meta Data"]["5. Time Zone"]?.ToString() }; // 映射TimeSeries var timeSeries = new TimeSeries(); var dailySeries = jObject["Time Series (Daily)"] as JObject; if (dailySeries != null) { foreach (var kvp in dailySeries) { var dataItem = kvp.Value as JObject; timeSeries.Data.Add(new Data { date = kvp.Key, series = "Daily", open = dataItem["1. open"]?.ToString(), high = dataItem["2. high"]?.ToString(), low = dataItem["3. low"]?.ToString(), close = dataItem["4. close"]?.ToString(), volume = dataItem["5. volume"]?.ToString() }); } } // 组装最终对象 var root = new Root { MetaData = metaData, TimeSeries = timeSeries };
方案二:自定义JsonConverter(适用于重复场景)
如果需要频繁处理此类JSON,可编写自定义转换器实现自动映射,避免重复代码:
1. MetaData转换器
public class MetaDataConverter : JsonConverter<MetaData> { public override MetaData ReadJson(JsonReader reader, Type objectType, MetaData existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); return new MetaData { Information = jObject["1. Information"]?.ToString(), Symbol = jObject["2. Symbol"]?.ToString(), LastRefreshed = jObject["3. Last Refreshed"]?.ToString(), OutputSize = jObject["4. Output Size"]?.ToString(), TimeZone = jObject["5. Time Zone"]?.ToString() }; } public override void WriteJson(JsonWriter writer, MetaData value, JsonSerializer serializer) { // 若无需序列化回原格式,可抛出异常或留空 throw new NotImplementedException(); } }
2. Root转换器
public class RootConverter : JsonConverter<Root> { public override Root ReadJson(JsonReader reader, Type objectType, Root existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var root = new Root { MetaData = new MetaDataConverter().ReadJson(jObject["Meta Data"].CreateReader(), typeof(MetaData), null, false, serializer), TimeSeries = new TimeSeries { Data = new List<Data>() } }; var dailySeries = jObject["Time Series (Daily)"] as JObject; if (dailySeries != null) { foreach (var kvp in dailySeries) { var dataItem = kvp.Value as JObject; root.TimeSeries.Data.Add(new Data { date = kvp.Key, series = "Daily", open = dataItem["1. open"]?.ToString(), high = dataItem["2. high"]?.ToString(), low = dataItem["3. low"]?.ToString(), close = dataItem["4. close"]?.ToString(), volume = dataItem["5. volume"]?.ToString() }); } } return root; } public override void WriteJson(JsonWriter writer, Root value, JsonSerializer serializer) { throw new NotImplementedException(); } }
3. 使用转换器反序列化
var settings = new JsonSerializerSettings(); settings.Converters.Add(new RootConverter()); var root = JsonConvert.DeserializeObject<Root>(rawJson, settings);
其他工具包建议
若使用.NET Core 3.0+,可选择System.Text.Json,实现思路与Newtonsoft一致:先解析为JsonDocument手动映射,或编写JsonConverter,仅API细节略有差异,无需额外引入第三方包。
内容的提问来源于stack exchange,提问作者bmich72
相关产品推荐
相关产品推荐

