2015-11-06 2 views
13

Wenn es in der .NET-Welt zur Objektserialisierung kommt, werden die Felder und Eigenschaften des Objekts zur Laufzeit untersucht. Die Verwendung von Reflektion für diesen Job ist normalerweise langsam und bei großen Objektmengen unerwünscht. Die andere Möglichkeit besteht in der Verwendung von IL-Emit- oder Build-Expression-Bäumen, die einen signifikanten Leistungsgewinn gegenüber der Reflektion bieten. Letzteres ist für die meisten modernen Bibliotheken bei der Serialisierung der Fall. Das Erstellen und Emittieren von IL zur Laufzeit benötigt jedoch Zeit, und die Investition wird nur zurückbezahlt, wenn diese Informationen zwischengespeichert und für Objekte des gleichen Typs wiederverwendet werden.Speichert Json.NET die Serialisierungsinformationen der Cachetypen?

Bei der Verwendung von Json.NET ist mir nicht klar, welche der oben beschriebenen Methoden verwendet wird, und ob letztere tatsächlich verwendet wird, ob das Caching verwendet wird.

Zum Beispiel, wenn ich das tue:

JsonConvert.SerializeObject(new Foo { value = 1 }); 

Does Json.NET das Mitglied, Informationen und Cache Foo bauen sie später wieder zu verwenden?

+4

Ich habe keine endgültige Antwort für Sie, aber die Quelle für [Json.NET] (https://github.com/JamesNK/Newtonsoft.Json) ist auf Github und es sagt, dass "Json.NET ist ein beliebtes Hochleistungs-JSON-Framework für .NET ". Wenn Sie eine schnelle Suche nach dem Cache auf der Quelle durchführen, werden Sie feststellen, dass tatsächlich eine Menge Caching stattfindet. – KiwiPiet

Antwort

12

Json.NET Caches Typ Serialisierung Informationen innerhalb seiner IContractResolver Klassen DefaultContractResolver und CamelCasePropertyNamesContractResolver. Sofern Sie keinen benutzerdefinierten Contract Resolver angeben, werden diese Informationen zwischengespeichert und wiederverwendet.

Für DefaultContractResolver wird intern eine globale statische Instanz gepflegt, die Json.NET verwendet, wenn die Anwendung keinen eigenen Vertragsresolver angibt. CamelCasePropertyNamesContractResolver dagegen verwaltet statische Tabellen, die für alle Instanzen freigegeben sind. (Ich glaube, dass die Inkonsistenz von Legacy-Problemen herrührt; siehe here für Details.)

Beide Typen sind so konzipiert, dass sie vollständig threadsicher sind, so dass das Teilen zwischen Threads kein Problem sein sollte.

Wenn Sie einen eigenen Vertragsresolver erstellen, werden die Typinformationen nur zwischengespeichert und wiederverwendet, wenn Sie die Contract Resolver-Instanz selbst zwischenspeichern und wiederverwenden. So für „stateless“ Resolver (diejenigen, die nicht ändern ihre Rückgabewerte auf der Grundlage der aktuellen Instanz serialisiert oder andere Laufzeitbedingungen), Newtonsoft recommends:

Cache-Instanzen des Auftrags Resolver in Ihrer Anwendung für eine optimale Performance.

Eine Strategie Caching in einer Unterklasse von DefaultContractResolver für die Gewährleistung ist Konstruktor zu machen geschützt oder privat sein, und eine globale statische Instanz zur Verfügung stellen. (. Natürlich ist dies nur dann sinnvoll ist, wenn der Resolver sollte immer die gleichen Ergebnisse angezeigt) zB durch this question inspiriert, hier ist ein pascal Fall Vertrags Resolver zu unterstreichen:

public class PascalCaseToUnderscoreContractResolver : DefaultContractResolver 
{ 
    protected PascalCaseToUnderscoreContractResolver() : base() { } 

    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons. 
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm 
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm 
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance." 
    static PascalCaseToUnderscoreContractResolver instance; 

    // Using an explicit static constructor enables lazy initialization. 
    static PascalCaseToUnderscoreContractResolver() { instance = new PascalCaseToUnderscoreContractResolver(); } 

    public static PascalCaseToUnderscoreContractResolver Instance { get { return instance; } } 

    static string PascalCaseToUnderscore(string name) 
    { 
     if (name == null || name.Length < 1) 
      return name; 
     var sb = new StringBuilder(name); 
     for (int i = 0; i < sb.Length; i++) 
     { 
      var ch = char.ToLowerInvariant(sb[i]); 
      if (ch != sb[i]) 
      { 
       if (i > 0) // Handle flag delimiters 
       { 
        sb.Insert(i, '_'); 
        i++; 
       } 
       sb[i] = ch; 
      } 
     } 
     return sb.ToString(); 
    } 

    protected override string ResolvePropertyName(string propertyName) 
    { 
     return PascalCaseToUnderscore(propertyName); 
    } 
} 

Wo möchten Sie verwenden:

var json = JsonConvert.SerializeObject(someObject, new JsonSerializerSettings { ContractResolver = PascalCaseToUnderscoreContractResolver.Instance }); 
+1

So löschen Sie diesen Cache – singsuyash