比较两个相同结构的任意JToken

比较两个相同结构的任意JToken,第1张

比较两个相同结构的任意JToken

在Linq-to-
JSON中,

JValue
表示原始值(字符串,数字,布尔值等)。它实现了
IComparable<JValue>
,因此Json.NET会为您处理原始值的排序

在此基础上,您将需要递归

JToken
并行地降低两个对象层次结构。当您遇到具有不同.Net类型,不同属性(如果不是
JValue
)或具有不同值(如果a
JValue
)的第一个标记时,您需要返回比较值。

请注意以下几点:

  • 比较方法应该是自反的,反对称的和可传递的。
  • 需要以某种一致的方式按类型对不同.Net类型的容器令牌进行排序。
  • 的孩子令牌
    JArray
    JConstructor
    排序。
  • 的子标记
    JObject
    不是,因此需要以稳定,对称的方式进行比较。以 属性名称的 顺序行走似乎是可行的。
  • 没有明显的比较方法
    JRaw
    ,所以不要尝试让异常抛出。

以下是原型实现:

public class JTokenComparer : IComparer<JToken>{    public static JTokenComparer Instance { get { return instance; } }    static JTokenComparer instance;    static JTokenComparer()    {        instance = new JTokenComparer();    }    readonly Dictionary<Type, KeyValuePair<int, IComparer<JToken>>> dict;    JTokenComparer()    {        dict = new Dictionary<Type, KeyValuePair<int, IComparer<JToken>>>        { // Order chosen semi-arbitrarily.  Putting values first seems reasonable though. {typeof(JValue), new KeyValuePair<int, IComparer<JToken>>(0, new JValueComparer()) }, {typeof(JProperty), new KeyValuePair<int, IComparer<JToken>>(1, new JPropertyComparer()) }, {typeof(JArray), new KeyValuePair<int, IComparer<JToken>>(2, new JArrayComparer()) }, {typeof(JObject), new KeyValuePair<int, IComparer<JToken>>(3, new JObjectComparer()) }, {typeof(JConstructor), new KeyValuePair<int, IComparer<JToken>>(4, new JConstructorComparer()) },        };    }    #region IComparer<JToken> Members    public int Compare(JToken x, JToken y)    {        if (x is JRaw || y is JRaw) throw new InvalidOperationException("Tokens of type JRaw cannot be sorted");        if (object.ReferenceEquals(x, y)) return 0;        else if (x == null) return -1;        else if (y == null) return 1;        var typeData1 = dict[x.GetType()];        var typeData2 = dict[y.GetType()];        int comp;        if ((comp = typeData1.Key.CompareTo(typeData2.Key)) != 0) return comp;        if (typeData1.Value != typeData2.Value) throw new InvalidOperationException("inconsistent dictionary values"); // Internal error        return typeData2.Value.Compare(x, y);    }    #endregion}abstract class JTokenComparerbase<TJToken> : IComparer<JToken> where TJToken : JToken{    protected TJToken CheckType(JToken item)    {        if (item != null && item.GetType() != typeof(TJToken)) throw new ArgumentException(string.Format("Actual type {0} of token "{1}" does not match expected type {2}", item.GetType(), item, typeof(TJToken)));        return (TJToken)item;    }    protected bool TrybaseCompare(TJToken x, TJToken y, out int comparison)    {        CheckType(x);        CheckType(y);        if (object.ReferenceEquals(x, y))        { comparison = 0; return true;        }        else if (x == null)        { comparison = -1; return true;        }        else if (y == null)        { comparison = 1; return true;        }        comparison = 0;        return false;    }    protected abstract int CompareDerived(TJToken x, TJToken y);    protected int TokenCompare(JToken x, JToken y)    {        var tx = CheckType(x);        var ty = CheckType(y);        int comp;        if (TrybaseCompare(tx, ty, out comp)) return comp;        return CompareDerived(tx, ty);    }    #region IComparer<JToken> Members    int IComparer<JToken>.Compare(JToken x, JToken y)    {        return TokenCompare(x, y);    }    #endregion}abstract class JContainerOrderedComparerbase<TJToken> : JTokenComparerbase<TJToken> where TJToken : JContainer{    protected int CompareItemsInOrder(TJToken x, TJToken y)    {        int comp;        // Dictionary order: sort on items before number of items.        for (int i = 0, n = Math.Min(x.Count, y.Count); i < n; i++) if ((comp = JTokenComparer.Instance.Compare(x[i], y[i])) != 0)     return comp;        if ((comp = x.Count.CompareTo(y.Count)) != 0) return comp;        return 0;    }}class JPropertyComparer : JTokenComparerbase<JProperty>{    protected override int CompareDerived(JProperty x, JProperty y)    {        int comp;        if ((comp = x.Name.CompareTo(y.Name)) != 0) return comp;        return JTokenComparer.Instance.Compare(x.Value, y.Value);    }}class JObjectComparer : JTokenComparerbase<JObject>{    protected override int CompareDerived(JObject x, JObject y)    {        int comp;        // Dictionary order: sort on items before number of items.        // Order both property sequences to preserve reflexivity.        foreach (var propertyComp in x.Properties().OrderBy(p => p.Name).Zip(y.Properties().OrderBy(p => p.Name), (xp, yp) => JTokenComparer.Instance.Compare(xp, yp))) if (propertyComp != 0)     return propertyComp;        if ((comp = x.Count.CompareTo(y.Count)) != 0) return comp;        return 0;    }}class JArrayComparer : JContainerOrderedComparerbase<JArray>{    protected override int CompareDerived(JArray x, JArray y)    {        int comp;        if ((comp = CompareItemsInOrder(x, y)) != 0) return comp;        return 0;    }}class JConstructorComparer : JContainerOrderedComparerbase<JConstructor>{    protected override int CompareDerived(JConstructor x, JConstructor y)    {        int comp;        if ((comp = x.Name.CompareTo(y.Name)) != 0) return comp;        if ((comp = CompareItemsInOrder(x, y)) != 0) return comp;        return 0;    }}class JValueComparer : JTokenComparerbase<JValue>{    protected override int CompareDerived(JValue x, JValue y)    {        return Comparer<JToken>.Default.Compare(x, y); // JValue implements IComparable<JValue>    }}

经过严格测试的原型小提琴。



欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/zaji/5090163.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-11-16
下一篇2022-11-16

发表评论

登录后才能评论

评论列表(0条)

    保存