【发布时间】:2018-10-12 13:40:56
【问题描述】:
我目前在使用 Newtonsoft Json 时遇到了一些问题。
我想要的很简单:将要序列化的对象与所有属性和子属性进行相等性比较。
我现在尝试创建自己的 EqualityComparer,但它只与父对象的属性进行比较。
另外,我尝试编写自己的 ReferenceResolver,但没有成功。
让我们用一个例子来谈谈:
public class EntityA
{
int Foo {get; set;}
public override bool Equals(object obj)
{
return (obj is EntityA other) && other.Foo == this.Foo;
}
}
public class EntityB
{
int Bar {get; set;}
EntityA Parent {get; set;}
public override bool Equals(object obj)
{
return (obj is EntityB other) && other.Bar == this.Bar;
}
}
public class InnerWrapper
{
public string FooBar {get; set;}
public EntityB BEntity {get; set;}
}
public class OuterClass
{
public EntityA AEntity { get; set;}
List<InnerWrapper> InnerElements {get; set;}
}
现在我想要的是从 EntityB 到 EntityA 的引用。在我的情况下,它们总是相同的。所以我期望的是,在每个 EntityB 的 JSON 中,对 EntityA 的引用都写为 ref。实体的相等覆盖相等以检查它们是否相同。它们是数据库对象,因此只要它们的 ID 相同,它们就相等。在这种情况下,我称它们为 Foo 和 Bar。
我尝试过的如下:
public class MyEqualComparer : IEqualityComparer
{
public bool Equals(object x, object y)
{
return x.Equals(y);
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
}
使用以下 JSON 设置
public static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
NullValueHandling = NullValueHandling.Ignore,
FloatParseHandling = FloatParseHandling.Decimal,
Formatting = Formatting.Indented,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
EqualityComparer = new MyEqualComparer(),
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
Error = (sender, args) => Log.Error(args.ErrorContext.Error, $"Error while (de)serializing: {args.ErrorContext}; object: {args.CurrentObject}")
};
但它不起作用。它比较完全错误的值。例如来自OuterClass 的EntityA 与InnerWrapper 中的每一个。但不是与属性甚至子属性(在本例中为InnerWrapper 的EntityB 的属性)。
使用自定义的 ReferenceResolver,我也没有运气,因为上面的设置非常通用,我不知道如何编写通用的。
您知道如何完成这项工作吗?
// 编辑:
下面是我所期望的示例:
{
"$id" : "1",
"AEntity": {
"$id": "2",
"Foo": 200
},
"InnerElements": [
{
"$id": "3",
"Bar": 20,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "4",
"Bar": 21,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "5",
"Bar": 23,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "6",
"Bar": 24,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "7",
"Bar": 25,
"Parent": {
"$ref" : "2"
}
}
]
}
这就是我得到的:
{
"$id" : "1",
"AEntity": {
"$id": "2",
"Foo": 200
},
"InnerElements": [
{
"$id": "3",
"Bar": 20,
"Parent": {
"$id": "8",
"Foo": 200
}
},
{
"$id": "4",
"Bar": 21,
"Parent": {
"$id": "9",
"Foo": 200
}
},
{
"$id": "5",
"Bar": 23,
"Parent": {
"$id": "10",
"Foo": 200
}
},
{
"$id": "6",
"Bar": 24,
"Parent": {
"$id": "11",
"Foo": 200
}
},
{
"$id": "7",
"Bar": 25,
"Parent": {
"$id": "12",
"Foo": 200
}
}
]
}
当然,在这种情况下,影响很小。但我的真实场景要大得多。
【问题讨论】:
-
简单来说就是比较两个json对象的属性和子属性。对吗?
-
不是两个 JSON 对象。在一个 JSON 对象中,另一个元素中有 EntityA。但是我在 OuterElement 的列表中有大约 thound 个条目。这些都包含对 OuterElement 的 EntityA 的引用。为了减小序列化 JSON 文件的大小,我希望引用外部元素。我将添加一个示例。
-
this answer 到 JSON.NET Serialization - How does DefaultReferenceResolver compare equality? 是否解释了编写自己的自定义引用解析器需要做什么?
JsonSerializerSettings.EqualityComparer用于参考循环检测,请参阅Why doesn't reference loop detection use reference equality?。 -
您好,感谢您的回答。我已经看过了。但问题就在那里,我不知道 T 的类型。因为(正如您在上面的简单类型中看到的)我有不同的类型。它应该始终采用 a.Equals(b)。所以这应该在对象基础上工作。我也用一个对象尝试过这个例子,但是一旦我有了结构,它就不再起作用了。
-
@CodeRain - 在这种情况下,您能否请edit 分享您迄今为止尝试过的问题,最好是您的自定义参考解析器的正在进行中的工作?如果您可以提供minimal reproducible example 显示您遇到的问题,您更有可能获得有用的答案。