C#加载JSON节点到字典并保留插入顺序的解决方案
保留JSON原始顺序读取为字典的解决方案
问题核心:你当前使用的ConfigurationBuilder内置JSON配置提供者,在加载配置时会自动对键进行字母排序,所以即使绑定到.NET 6+的Dictionary<string, string>(该版本后字典默认保留插入顺序),也无法得到JSON里的原始顺序。
以下是两种可行解决方案:
方案1:直接用JSON序列化库读取(推荐,简单高效)
绕过Configuration系统,直接用JSON库读取文件并按原始顺序构建字典,以Newtonsoft.Json为例:
- 先通过NuGet安装
Newtonsoft.Json包 - 替换原读取代码为:
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
相关产品推荐
相关产品推荐

