C# JSON属性排序、比较 Newtonsoft.Json

用法目的

  1. 对比两个JSON对象是否完全相等
  2. 用于参数匹配

排序 实现代码:

cs 复制代码
// JsonHelper.cs
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public static class JsonHelper
{
    
    /// <summary>
    /// 对JSON属性进行升序排序
    /// </summary>
    public static JToken GetSortedObject(JToken obj)
    {
        if (obj is JArray jArray)
        {
            var jArray2 = new JArray();
            foreach (var item in jArray)
            {
                jArray2.Add(GetSortedObject(item));
            }
            return jArray2;
        }
        else if (obj is JObject jObject)
        {
            var sortedDic = new SortedDictionary<string, JToken>();
            foreach (var jProperty in jObject.Properties())
            {
                if (jProperty.Value is JArray || jProperty.Value is JObject)
                {
                    sortedDic.Add(jProperty.Name, GetSortedObject(jProperty.Value));
                }
                else
                {
                    sortedDic.Add(jProperty.Name, jProperty.Value);
                }
            }

            var newJObject = new JObject();
            foreach ((var key, var value) in sortedDic)
            {
                newJObject.Add(key, value);
            }

            return newJObject;
        }
        else
        {
            return obj;
        }
    }
}

比较实现代码

cs 复制代码
// JsonHelper.cs
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public static class JsonHelper
{
    
    public static bool JValueEquals(JToken? obj1, JToken? obj2)
    {
        if (obj1 is JArray jArray && obj2 is JArray jArray2)
        {
            var jarr2_items = jArray2.ToList();
            foreach (var item1 in jArray)
            {
                var item2 = jarr2_items.PickItem(x => JValueEquals(item1, x));
                if (item2 is null)
                {
                    return false;
                }
            }

            return true;
        }
        else if (obj1 is JObject jObject && obj2 is JObject jObject2)
        {
            var j2_props = jObject2.Properties().ToList();
            foreach (var p1 in jObject.Properties())
            {
                var p2 = j2_props.FirstOrDefault(x => x.Name == p1.Name);
                if (p2 is null || !JValueEquals(p1.Value, p2.Value))
                {
                    return false;
                }
            }

            return true;
        }
        else if (obj1 is JValue v1 && obj2 is JValue v2)
        {
            if ((v1.Type == JTokenType.Float && (v2.Type == JTokenType.Float || v2.Type == JTokenType.Integer))
                || v2.Type == JTokenType.Float && v1.Type == JTokenType.Integer)
            {
                if (v1.Value == v2.Value)
                {
                    return true;
                }

                if (v1.Value == null || v2.Value == null)
                {
                    return false;
                }

                var d1 = v1.Type == JTokenType.Integer ? (long)v1.Value : (double)v1.Value;
                var d2 = v2.Type == JTokenType.Integer ? (long)v2.Value : (double)v2.Value;

                return DoubleEqual(d1, d2);
            }

            if (v1.Type == JTokenType.Integer && v2.Type == JTokenType.Integer)
            {
                if (v1.Value == v2.Value)
                {
                    return true;
                }

                if (v1.Value == null || v2.Value == null)
                {
                    return false;
                }

                return (long)v1.Value == (long)v2.Value;
            }

            return Object.Equals(v1.Value, v2.Value);
        }

        return Object.Equals(obj1, obj2);
    }
    
    /// <summary>
    /// 浮点数相等
    /// </summary>
    /// <param name="d"></param>
    /// <param name="d2"></param>
    /// <returns></returns>
    public static bool DoubleEqual(double? d, double? d2)
    {
        // https://learn.microsoft.com/zh-cn/dotnet/api/system.double.epsilon?view=net-7.0
        // ReSharper disable once CompareOfFloatsByEqualityOperator
        return d == d2 || (d.HasValue && d2.HasValue && Math.Abs(d.Value - d2.Value) < (2.2250738585072014E-308));
    }
}

// IListExtension.cs
using System.Collections.ObjectModel;
public static class IListExtension
{
   public static T? PickItem<T>(this IList<T> list, Predicate<T> predicate)
    {
        T data;
        for (int i = 0; i < list.Count; i++)
        {
            if (predicate(list[i]))
            {
                data = list[i];
                list.RemoveAt(i);
                return data;
            }
        }

        return default(T?);
    }
}
相关推荐
子洋20 分钟前
AI Agent 介绍
前端·人工智能·后端
粟悟饭&龟波功1 小时前
【GitHub热门项目精选】(2025-12-19)
前端·人工智能·后端·github
不思念一个荒废的名字2 小时前
【黑马JavaWeb+AI知识梳理】Web后端开发04-登录认证
java·后端
平凡运维之路2 小时前
Linux入侵挖矿处理记录
后端
王中阳Go2 小时前
15 Go Eino AI应用开发实战 | 性能优化
后端·面试·go
shoubepatien3 小时前
JAVA -- 07
java·后端·intellij-idea
王中阳Go3 小时前
09 Go Eino AI应用开发实战 | Hertz Web 框架搭建
人工智能·后端·go
無量3 小时前
ConcurrentHashMap实现原理
java·后端
vipbic3 小时前
Strapi 5 怎么用才够爽?这款插件带你实现“建站自由”
后端·node.js
苏三的开发日记4 小时前
linux搭建hadoop服务
后端