2014-08-29 110 views
4

我正在使用JSON.NET 6.0.3。我已經改變PreserveReferences選項如下:JSON.NET序列化 - DefaultReferenceResolver如何比較相等性?

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,然後創建傳遞CarManufacturer的CarFromManufacturer實例......我正在創建一個CarManufacturer的新實例。這可以解釋爲什麼對象不相等,但這就是爲什麼我實現了IEquatable並重寫base.Equals(object)和base.GetHashCode()。

我看着到source for DefaultReferenceResolver並使用它使用EqualityComparer.Default其中,從MSDN documentation,採用T的執行IEquatable,如果它不存在,或者以其他方式使用T的base.Equals()執行default constructor of BidirectionalDictionary ....所有這一切都會讓我相信CarManufacturer中的IEquatable能夠解決我的問題。然而,在CarManufacturer.Equals()和GethashCode()中放置斷點從未命中..

+0

爲什麼我創建制造商的一個新實例每次都是因爲我的工廠對象發生在連接表記錄的EF實體的原因(加入汽車和製造商)..所以它從EF Car對象構建汽車,並通過EF製造商調用ManufacturerFactory。 – diegohb 2014-08-29 11:59:53

+0

看起來像是比較對象引用的相等性。實施IReferenceResolver有什麼問題? – 2014-08-29 13:40:45

+0

感謝您的意見!重寫Equals和GetHashCode不足以讓JSON.NET的DefaultReferenceResolver知道如何比較對象嗎?實施IReferenceResolver沒什麼問題,除非我不需要額外的複雜性,如果它不是這個問題的話。我寧願在做這件事之前重組工廠代碼。但問題是關於DefaultReferenceResolver如何比較相等性。我正在更新帖子.. – diegohb 2014-08-29 16:21:58

回答

2

JSON.NET默認解析引用的邏輯只是使用this comparer來比較引用。

如果要以不同方式比較對象,則必須實施自定義IReferenceResolver

下面是需要一個IEqualityComparer<T>,以適應您的使用情況的一個例子:

public class ReferenceResolver<T> : IReferenceResolver 
{ 
    private Dictionary<string, T> stringToReference; 
    private Dictionary<T, string> referenceToString; 

    private int referenceCount; 

    public ReferenceResolver(IEqualityComparer<T> comparer) 
    { 
     this.stringToReference = new Dictionary<string, T>(); 
     this.referenceToString = new Dictionary<T, string>(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; 
    } 
} 
+0

非常感謝!理想情況下,解析器可以全局應用於HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.ReferenceResolver並使用依賴關係解析。我將大膽地假設所有將被序列化的模型對象都是不可變的,所以因此ReferenceEquality並不重要 - 用於序列化的目的。謝謝! – diegohb 2014-08-29 17:59:27

+0

如果你有任何見解... ... https://github.com/JamesNK/Newtonsoft.Json/issues/411 – diegohb 2014-11-02 17:38:59

0

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(); 
     } 
    } 
+0

這也在這裏討論:https://github.com/JamesNK/Newtonsoft.Json/issues/401 – 2015-08-04 06:32:52