模糊深度对象比较

4

我有一个方法,它返回了一个非常庞大的对象,其中有很多字段。就像这样:

{
    Success: true,
    Timestamp: "07.03.2014",
    Items:
    [
        {
            Name: "A",
            Price: 13.37,
            OtherData: 123
        },
        {
            Name: "B",
            Price: 42,
            OtherData: 312
        }
    ]
}

我希望在.NET应用程序中进行测试时,将其返回值与参考值进行比较。然而,这里有几个问题:

  • Timestamp字段每次都会更改
  • Price字段中的舍入也可能会有所不同
  • Items的顺序并不重要

我想以最灵活的方式定义参考对象:

  • 省略不必要的字段
  • 能够指定规则(字符串的正则表达式、数字的范围/舍入等)而非仅仅是值

以下是参考定义的示例:

{
    Success: true,
    Items:
    [
        {
            Name: "A",
            Price: "13.37",
        },
        {
            Name: "B",
            Price: 42,
        }
    ]
}

有没有适用于.NET的库,可以进行这种比较?
1个回答

2
最终我决定自己实现比较功能。以下是代码,希望对某些人有所帮助:

public static class Utils
{
    public static bool SequencesMatch<TSource, TPattern>(IEnumerable<TSource> sequence, IEnumerable<TPattern> patterns, Func<TSource, TPattern, bool> matcher)
    {
        var items = sequence.Select(x => new SequenceItem<TSource>(x)).ToArray();
        var pats = patterns.Select(x => new SequenceItem<TPattern>(x)).ToArray();

        foreach (var item in items)
        {
            foreach (var pat in pats)
            {
                if (pat.Matched) continue;
                if (matcher(item.Value, pat.Value))
                {
                    item.Matched = pat.Matched = true;
                    break;
                }
            }
        }

        return items.All(x => x.Matched) && pats.All(x => x.Matched);
    }

    public static bool JsonObjectsMatch(JToken data, JToken reference)
    {
        if (reference.Type == JTokenType.Array)
            return SequencesMatch(data, reference, JsonObjectsMatch);

        if (reference.Type == JTokenType.Object)
        {
            var dataObj = data as JObject;
            var refObj = reference as JObject;

            if (dataObj == null || refObj == null)
                Assert.Fail("DataObject = '{0}', ReferenceObject = '{1}'", dataObj, refObj);

            foreach (var pty in refObj)
            {
                var dataValue = dataObj[pty.Key];
                if (dataValue == null || !JsonObjectsMatch(dataValue, pty.Value))
                    Assert.Fail("Objects differ at {0}: DataValue = '{1}', RefValue = '{2}'", pty.Key, dataValue, pty.Value);
            }

            return true;
        }

        if (reference.Type == JTokenType.Float)
        {
            var refFloat = reference.ToObject<float>();
            var dataFloat = data.ToObject<float>();

            if(Math.Abs(dataFloat - refFloat) > 0.001)
                Assert.Fail("Objects differ: DataValue = '{0}', RefValue = '{1}'", dataFloat, refFloat);

            return true;
        }

        return JToken.DeepEquals(data, reference);
    }

    private class SequenceItem<T>
    {
        public T Value { get; set; }
        public bool Matched { get; set; }

        public SequenceItem(T value)
        {
            Value = value;
        }
    }
}

我可能应该在有足够时间后将其制作成一个正式的库,并发布到GitHub上。


是的,你应该这样做。我可以看到一些使用这个函数的情况 :) - ForNeVeR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接