使用Json.NET时,不清楚我可以使用上述哪种方法,如果确实使用了后者,则是否使用缓存。例如,当我这样做时:
JsonConvert.SerializeObject(new Foo { value = 1 });
Json.NET是否可以构建Foo的成员访问信息并缓存以备将来使用?
#1 楼
是的,它确实。 Json.NET在其IContractResolver
类DefaultContractResolver
和CamelCasePropertyNamesContractResolver
内部缓存类型序列化信息。除非指定自定义合同解析器,否则此信息将被缓存和重用。对于DefaultContractResolver
,只要应用程序未指定其自己的合同解析器,Json.NET就会在内部维护全局静态实例。另一方面,CamelCasePropertyNamesContractResolver
维护在所有实例之间共享的静态表。 (我认为不一致是由遗留问题引起的;有关详细信息,请参见此处。)这两种类型均被设计为完全线程安全的,因此线程之间的共享不成问题。
如果您选择实现和实例化自己的合同解析器,则仅当您缓存和重用合同解析器实例本身时,类型信息才会被缓存和重用。因此,Newtonsoft建议:为了提高性能,您应该创建一个合同解析器,并在可能的情况下重用实例。解决合同的速度很慢,并且IContractResolver的实现通常会缓存合同。自己的
DefaultContractResolver
(或某些自定义子类)本地实例,使用它进行序列化,然后立即删除对其的所有引用,例如:public class JsonExtensions
{
public static string SerializeObjectNoCache<T>(T obj, JsonSerializerSettings settings = null)
{
settings = settings ?? new JsonSerializerSettings();
bool reset = (settings.ContractResolver == null);
if (reset)
// To reduce memory footprint, do not cache contract information in the global contract resolver.
settings.ContractResolver = new DefaultContractResolver();
try
{
return JsonConvert.SerializeObject(obj, settings);
}
finally
{
if (reset)
settings.ContractResolver = null;
}
}
}
CamelCasePropertyNamesContractResolver,例如:
settings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
大部分缓存的协定内存(但不是全部)最终都会被垃圾回收。当然,这样做会严重影响序列化性能。 (某些包含有关
DefaultContractResolver
类型和数据协定属性的反映信息的表是全局共享的,不会被回收。)有关更多信息,请参阅Newtonsoft的性能提示:重用合同解析器。
评论
我们在所有UT中看到保存在MyContractResolver:CamelCasePropertyNamesContractResolver类型中的合同是静态缓存的,即使跨多个MyContractResolver类型也是如此。当一些UT一起运行时,这会导致令人惊讶的混乱,因为它们没有根据需要设置合同。重用同一ContractResolver实例的指针仍然有效吗?
– ElFik
4月1日1:26
@ElFik-CamelCasePropertyNamesContractResolver的行为与DefaultContractResolver不同-不管是否需要,它都会全局缓存合同信息。如果您不想这样做,请使用适当的命名策略切换到DefaultContractResolver。
–dbc
5月5日19:54
评论
我没有确切的答案,但是Json.NET的源代码位于github上,它确实说“ Json.NET是.NET的流行高性能JSON框架”。如果您在源上快速搜索缓存,则会发现确实存在大量缓存。