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

C#加载JSON节点到字典并保留插入顺序的解决方案

保留JSON原始顺序读取为字典的解决方案

问题核心:你当前使用的ConfigurationBuilder内置JSON配置提供者,在加载配置时会自动对键进行字母排序,所以即使绑定到.NET 6+的Dictionary<string, string>(该版本后字典默认保留插入顺序),也无法得到JSON里的原始顺序。

以下是两种可行解决方案:

方案1:直接用JSON序列化库读取(推荐,简单高效)

绕过Configuration系统,直接用JSON库读取文件并按原始顺序构建字典,以Newtonsoft.Json为例:

  1. 先通过NuGet安装Newtonsoft.Json包
  2. 替换原读取代码为:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.IO;

// 读取JSON文件内容
string jsonContent = File.ReadAllText("settings.json");
// 解析JSON对象
var rootObj = JsonConvert.DeserializeObject<JObject>(jsonContent);
// 遍历"MyJson"节点的属性(按JSON原始顺序),构建字典
var myDict = rootObj["MyJson"]
    .Children<JProperty>()
    .ToDictionary(p => p.Name, p => p.Value.ToString());

JProperty的遍历顺序严格遵循JSON文件中的原始顺序,因此构建的.NET 6+ Dictionary会保留该顺序;如果用更早版本的.NET,建议改用System.Collections.Specialized.OrderedDictionary来存储。

方案2:自定义JSON配置提供者(依赖Configuration系统时使用)

如果你必须借助Configuration系统的功能(比如配置重载、多源合并等),可以自定义一个不排序键的JSON配置提供者:

自定义Provider和Source代码

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Text.Json;

public class UnorderedJsonConfigurationProvider : JsonConfigurationProvider
{
    public UnorderedJsonConfigurationProvider(JsonConfigurationSource source) : base(source)
    {
    }

    public override void Load(Stream stream)
    {
        var jsonDocument = JsonDocument.Parse(stream);
        if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object)
        {
            throw new FormatException("JSON根节点必须是对象类型");
        }
        Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        // 直接遍历JObject属性,不排序
        VisitJObject(JObject.Parse(jsonDocument.RootElement.GetRawText()), string.Empty);
    }

    private void VisitJObject(JObject jObject, string path)
    {
        foreach (var property in jObject.Properties())
        {
            var propertyPath = string.IsNullOrEmpty(path) ? property.Name : $"{path}:{property.Name}";
            if (property.Value is JObject childObj)
            {
                VisitJObject(childObj, propertyPath);
            }
            else if (property.Value is JArray childArray)
            {
                VisitJArray(childArray, propertyPath);
            }
            else
            {
                Data[propertyPath] = property.Value.ToString();
            }
        }
    }

    private void VisitJArray(JArray jArray, string path)
    {
        for (int index = 0; index < jArray.Count; index++)
        {
            var element = jArray[index];
            var elementPath = $"{path}:{index}";
            if (element is JObject childObj)
            {
                VisitJObject(childObj, elementPath);
            }
            else if (element is JArray childArray)
            {
                VisitJArray(childArray, elementPath);
            }
            else
            {
                Data[elementPath] = element.ToString();
            }
        }
    }
}

public class UnorderedJsonConfigurationSource : JsonConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        EnsureDefaults(builder);
        return new UnorderedJsonConfigurationProvider(this);
    }
}

使用自定义配置源

var configuration = new ConfigurationBuilder()
    .Add(new UnorderedJsonConfigurationSource 
    { 
        Path = "settings.json", 
        ReloadOnChange = true,
        Optional = false
    })
    .Build();
// 绑定到字典即可保留原始顺序
myDict = configuration.GetSection("MyJson").Get<Dictionary<string, string>>();

内容的提问来源于stack exchange,提问作者Jaspreet Kaur Banwait

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 07:53:11