You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:50:53