Serializzazione JSON.NET – In che modo DefaultReferenceResolver confronta l’uguaglianza?

Sto usando JSON.NET 6.0.3. Ho cambiato l’opzione PreserveReferences come segue:

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

Il mio object grafico è simile al seguente:

 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; } } 

Il mio controller WebAPI restituisce il set di risultati di IEnumerable [CarFromManufacturer]. Quindi il risultato potrebbe essere un elenco di 5 auto di due oggetti unici del produttore. Mi aspetto che il risultato JSON elencherà ogni produttore solo una volta completamente serializzato e quindi gli usi successivi dello stesso produttore da $ ref ID al $ id originale. Non sta succedendo.

Anche se non riesco a trovare un singolo pezzo di documentazione che parli di come viene stabilita l’uguaglianza per ReferenceResolver, ho implementato IEquatable insieme a override di base.Equals e base.GetHashCode () senza fortuna.

Mi piacerebbe evitare di implementare il mio IReferenceResolver perché grafici di oggetti molto simili funzionano come previsto nello stesso progetto.

L’unica cosa che posso pensare è che sto usando oggetti di fabbrica e invece di creare prima ciascun CarManufacturer unico, quindi creare le istanze di CarFromManufacturer che passa in CarManufacturer … sto creando una nuova istanza di CarManufacturer. Questo spiegherebbe perché gli oggetti non sono uguali, ma è per questo che ho implementato IEquatable e override di base.Equals (object) e base.GetHashCode ().

Ho esaminato l’ origine di DefaultReferenceResolver e utilizza il costruttore predefinito di BidirectionalDictionary che utilizza EqualityComparer.Default che, dalla documentazione MSDN , utilizza l’implementazione T di IEquatable se esiste, o altrimenti utilizza l’implementazione di base.Equals () di T. .. tutto questo mi porterebbe a credere che IEquatable in CarManufacturer dovrebbe risolvere il mio problema. Tuttavia, posizionare i breakpoint in CarManufacturer.Equals () e GethashCode () non ha mai colpito ..

La logica di JSON.NET per la risoluzione dei riferimenti per impostazione predefinita confronta solo i riferimenti utilizzando questo comparatore .

Se si desidera confrontare gli oggetti in un modo diverso, sarà necessario implementare un IReferenceResolver personalizzato.

Ecco un esempio che accetta un IEqualityComparer per soddisfare il tuo caso d’uso:

 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 chiamerà il metodo Equals sugli oggetti da confrontare. In alcuni scenari potresti non volerlo, ad esempio quando controlla i riferimenti circolari fa lo stesso, mentre potrebbe essere più ideale controllare l’uguaglianza di riferimento. Lo fanno comunque per dare pieno controllo allo sviluppatore sovrascrivendo il metodo Equals nelle loro classi.

È ansible sovrascrivere l’implementazione predefinita. Ad esempio, per rendere questa un’eguaglianza di riferimento, procedere come segue:

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