¿La información de serialización de los tipos de caché Json.NET?

En .NET world, cuando se trata de serialización de objetos, por lo general va a inspeccionar los campos y propiedades del objeto en tiempo de ejecución. El uso de la reflexión para este trabajo suele ser lento y no es deseable cuando se trata de grandes conjuntos de objetos. La otra forma es usar IL emitir o construir árboles de expresión que proporcionen una ganancia de rendimiento significativa sobre la reflexión. Y el último es la selección de bibliotecas más modernas cuando se trata de serialización. Sin embargo, construir y emitir IL en tiempo de ejecución lleva tiempo, y la inversión solo se devuelve si esta información se almacena en caché y se reutiliza para objetos del mismo tipo.

Cuando uso Json.NET, no me queda claro qué método descrito anteriormente se usa, y si este último se usa, si se usa el almacenamiento en caché.

Por ejemplo, cuando lo hago:

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

¿Json.NET crea la información de acceso y la memoria caché de miembros de Foo para volver a utilizarla más tarde?

Json.NET almacena información de serialización de tipo dentro de sus clases IContractResolver DefaultContractResolver y CamelCasePropertyNamesContractResolver . A menos que especifique una resolución de contrato personalizada, esta información se almacena en caché y se reutiliza.

Para DefaultContractResolver se mantiene internamente una instancia global estática que Json.NET utiliza siempre que la aplicación no especifique su propia resolución de contrato. CamelCasePropertyNamesContractResolver , por otro lado, mantiene tablas estáticas que se comparten en todas las instancias. (Creo que la inconsistencia se debe a problemas heredados; consulte aquí para obtener detalles).

Ambos tipos están diseñados para ser totalmente seguros para subprocesos, por lo que compartirlos entre subprocesos no debería ser un problema.

Si elige crear su propia resolución de contrato, entonces la información de tipo solo se almacenará en caché y se reutilizará si guarda en caché y reutiliza la instancia de resolución de contrato. Por lo tanto, para los resolvedores “sin estado” (unos que no modifican sus valores de retorno basados ​​en la instancia actual que se está serializando u otras condiciones de tiempo de ejecución), Newtonsoft recomienda :

Instancias de caché de la resolución de contrato dentro de su aplicación para un rendimiento óptimo.

Una estrategia para garantizar el almacenamiento en caché en una subclase de DefaultContractResolver es hacer que su constructor esté protegido o sea privado, y proporcionar una instancia global estática. (Por supuesto, esto solo es apropiado si el resolvedor siempre devuelve los mismos resultados.) Por ejemplo, inspirado por esta pregunta , aquí hay un caso pascal para subrayar la resolución del contrato:

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

Que usarías como:

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