如何在C# 7中递归遍历JSON文档并对所有数值类型执行取整操作?
解决JSON递归数值取整问题
一、基于JsonDocument的递归实现(兼容C#7)
你的现有代码仅处理了两层对象结构,要实现全层级递归遍历,需编写递归方法处理所有类型的JsonElement(对象、数组、数字等)。以下是完整实现:
核心递归处理方法
private static void ProcessJsonElement(JsonElement element, Utf8JsonWriter writer, int roundDigits) { switch (element.ValueKind) { case JsonValueKind.Object: writer.WriteStartObject(); foreach (var property in element.EnumerateObject()) { writer.WritePropertyName(property.Name); ProcessJsonElement(property.Value, writer, roundDigits); } writer.WriteEndObject(); break; case JsonValueKind.Array: writer.WriteStartArray(); foreach (var item in element.EnumerateArray()) { ProcessJsonElement(item, writer, roundDigits); } writer.WriteEndArray(); break; case JsonValueKind.Number: // 执行Math.Round取整,同时兼容不同数字类型 if (element.TryGetDouble(out double value)) { var roundedValue = Math.Round(value, roundDigits); // 自动判断是否保留小数位,避免整数显示为带.0的浮点数 if (roundedValue == (int)roundedValue) { writer.WriteNumberValue((int)roundedValue); } else { writer.WriteNumberValue(roundedValue); } } else { // 处理无法转换为double的超大整数,直接保留原始值避免精度丢失 element.WriteTo(writer); } break; default: // 字符串、布尔值、null等类型直接原样写入 element.WriteTo(writer); break; } }
调用递归方法的主函数
修改原有方法,支持根节点为对象或数组,同时调用递归逻辑:
public static string ApplyRounding(string originalJson, int roundDigits = 15) { using var ms = new MemoryStream(); using var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = false, SkipValidation = true }); using var jsonDocument = JsonDocument.Parse(originalJson); var root = jsonDocument.RootElement; ProcessJsonElement(root, writer, roundDigits); writer.Flush(); return Encoding.UTF8.GetString(ms.ToArray()); }
关键特性
- 递归遍历JSON所有层级,包括嵌套对象、数组内的数字
- 智能处理数字格式,整数不会被强制转为浮点数
- 兼容超大整数场景,避免精度丢失
二、关于JsonNode的说明
你提到的JsonNode是.NET 6及以上版本才引入的API,而C#7对应的.NET版本(如.NET Core 2.x、.NET Framework 4.x)并不支持该类型。若你的项目可以升级到.NET 6+(建议同步升级C#到10+),可以使用更直观的原地修改方案:
public static string ApplyRoundingWithJsonNode(string originalJson, int roundDigits = 15) { var node = JsonNode.Parse(originalJson); ProcessJsonNode(node, roundDigits); return node.ToJsonString(new JsonSerializerOptions { WriteIndented = false }); } private static void ProcessJsonNode(JsonNode node, int roundDigits) { switch (node) { case JsonObject obj: // 转为List避免遍历中修改集合引发异常 foreach (var property in obj.ToList()) { ProcessJsonNode(property.Value, roundDigits); } break; case JsonArray array: for (int i = 0; i < array.Count; i++) { ProcessJsonNode(array[i], roundDigits); } break; case JsonValue value when value.ValueKind == JsonValueKind.Number: if (value.TryGetValue<double>(out double num)) { var rounded = Math.Round(num, roundDigits); // 替换原节点值,自动适配整数/浮点数格式 if (rounded == (int)rounded) { value.ReplaceWith((int)rounded); } else { value.ReplaceWith(rounded); } } break; // 其他类型无需处理 } }
说明
JsonNode支持原地修改JSON结构,代码逻辑更简洁直观- 仅适用于.NET 6及以上版本的项目
内容的提问来源于stack exchange,提问作者Dutts
相关产品推荐
相关产品推荐

