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?);
    }
}
相关推荐
小鸡脚来咯25 分钟前
SpringBoot 常用注解通俗解释
java·spring boot·后端
豌豆花下猫33 分钟前
Python 3.14 t-string 要来了,它与 f-string 有何不同?
后端·python·ai
小奏技术38 分钟前
Spring7将正式弃用Junit 4,我们也是时候迁移到Junit5了
后端
吴佳浩1 小时前
Python入门指南(四)-项目初始化
人工智能·后端·python
一颗知足的心1 小时前
Go语言之路————指针、结构体、方法
开发语言·后端·golang
蓝易云2 小时前
在Linux、CentOS7中设置shell脚本开机自启动服务
前端·后端·centos
一千柯橘3 小时前
Nestjs 解决 request entity too large
javascript·后端
userkang3 小时前
消失的前后端,崛起的智能体
前端·人工智能·后端·ai·硬件工程
慧一居士3 小时前
Kafka HA集群配置搭建与SpringBoot使用示例总结
spring boot·后端·kafka