JSON.NET序列化 – DefaultReferenceResolver如何比较相等?

我正在使用JSON.NET 6.0.3。 我更改了PreserveReferences选项,如下所示:

HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects; 

我的对象图类似于以下内容:

 public class CarFromManufacturer { public int CarID { get; set; } public string Make { get; set; } public string Model { get; set; } public CarManufacturer Manufacturer { get; set; } } public class CarManufacturer { public int ManufacturerID { get; set; } public string Name { get; set; } } 

我的WebAPI控制器返回IEnumerable [CarFromManufacturer]的结果集。 因此,结果可能是来自两个独特制造商对象的5辆汽车的列表。 我希望JSON结果只列出每个制造商一次完全序列化后,然后使用同一制造商将$ ref ID作为原始的$ id。 那没有发生。

即使我找不到单一文档来说明如何为ReferenceResolver建立相等性,我已经实现了IEquatable以及base.Equals和base.GetHashCode()的覆盖而没有运气。

我想避免实现我自己的IReferenceResolver,因为在同一个项目中有非常相似的对象图按预期工作。

我唯一能想到的是我正在使用工厂对象,而不是先创建每个独特的CarManufacturer,然后创建CarFufacturer中传递CarFromManufacturer的实例…我正在创建CarManufacturer的新实例。 这可以解释为什么对象不相等,但这就是我实现IEquatable并覆盖base.Equals(object)和base.GetHashCode()的原因。

我查看了DefaultReferenceResolver的源代码 ,它使用BidirectionalDictionary的默认构造函数,它使用EqualityComparer.Default,从MSDN文档中 ,如果它存在,则使用T的IEquatable实现,否则使用T的base.Equals()实现。 ..所有这一切都会让我相信CarManufacturer中的IEquatable应该解决我的问题。 但是,在CarManufacturer.Equals()和GethashCode()中放置断点从未命中..

默认情况下,JSON.NET用于解析引用的逻辑仅比较使用此比较器的引用。

如果要以不同方式比较对象,则必须实现自定义IReferenceResolver

这是一个使IEqualityComparer适应您的用例的示例:

 public class ReferenceResolver : IReferenceResolver { private Dictionary stringToReference; private Dictionary referenceToString; private int referenceCount; public ReferenceResolver(IEqualityComparer comparer) { this.stringToReference = new Dictionary(); this.referenceToString = new Dictionary(comparer); this.referenceCount = 0; } public void AddReference( object context, string reference, object value) { this.referenceToString.Add((T)value, reference); this.stringToReference.Add(reference, (T)value); } public string GetReference( object context, object value) { string result = null; if (!this.referenceToString.TryGetValue((T)value, out result)) { referenceCount++; result = referenceCount.ToString(CultureInfo.InvariantCulture); this.referenceToString.Add((T)value, result); this.stringToReference.Add(result, (T)value); } return result; } public bool IsReferenced( object context, object value) { return this.referenceToString.ContainsKey((T)value); } public object ResolveReference( object context, string reference) { T r = default(T); this.stringToReference.TryGetValue(reference, out r); return r; } } 

Json.Net将在被比较的对象上调用Equals方法。 在某些情况下,您可能不希望这样,例如,当它检查循环引用时,它会执行相同的操作,而检查引用相等性可能更为理想。 但是,他们这样做是为了通过在类中覆盖Equals方法来让开发人员完全控制。

您可以覆盖默认实现。 例如,为了使它成为引用相等,您将执行以下操作:

 var settings = new JsonSerializerSettings { EqualityComparer = new DefaultEqualityComparer(), }; public class DefaultEqualityComparer : IEqualityComparer { public bool Equals(object x, object y) { return ReferenceEquals(x, y); } public int GetHashCode(object obj) { return obj.GetHashCode(); } }