c# - Json.NET 是否缓存类型的序列化信息?

标签 c# json serialization json.net expression-trees

在 .NET 世界中,当谈到对象序列化时,通常会在运行时检查对象的字段和属性。为这项工作使用反射通常很慢,并且在处理大量对象时是不可取的。另一种方法是使用 IL emit 或构建表达式树,它们比反射提供显着的性能增益。后者是大多数现代图书馆在处理序列化时选择的。但是,在运行时构建和发出 IL 需要时间,只有缓存此信息并将其重新用于相同类型的对象,投资才能得到返回。

在使用Json.NET时,我不清楚使用的是上述哪种方法,如果确实使用了后者,是否使用了缓存。

例如,当我这样做时:

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

Json.NET 是否构建 Foo 的成员访问信息并缓存以备日后重用?

最佳答案

是的,确实如此。Json.NET 在其 IContractResolver 中缓存类型序列化信息。类(class) DefaultContractResolverCamelCasePropertyNamesContractResolver .除非您指定自定义契约(Contract)解析器,否则此信息将被缓存并重复使用。

对于 DefaultContractResolver,在内部维护一个全局静态实例,只要应用程序未指定其自己的契约(Contract)解析器,Json.NET 就会使用该实例。另一方面,CamelCasePropertyNamesContractResolver 维护所有实例共享的静态表。 (我认为不一致是由遗留问题引起的;有关详细信息,请参阅 here。)

这两种类型都设计为完全线程安全的,因此线程之间的共享应该不是问题。

如果您选择实现和实例化您自己的契约(Contract)解析器,那么类型信息只有在您缓存和重用契约(Contract)解析器实例本身时才会被缓存和重用。因此,Newtonsoft recommends :

For performance you should create a contract resolver once and reuse instances when possible. Resolving contracts is slow and implementations of IContractResolver typically cache contracts.

如果内存消耗是一个问题,并且出于任何原因您需要最小化缓存合约永久占用的内存,您可以构建自己的 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,请切换到带有适当 naming strategyDefaultContractResolver比如:

settings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };

大部分缓存的合约内存( but not all )最终会被垃圾回收。当然,通过这样做,序列化性能可能会受到很大影响。 (一些包含有关例如 enum 类型和数据协定属性的反射(reflect)信息的表是全局共享的,不会被回收。)

有关更多信息,请参阅 Newtonsoft 的 Performance Tips: Reuse Contract Resolver .

关于c# - Json.NET 是否缓存类型的序列化信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33557737/

相关文章:

c# - 如何在 xamarin 表单中启用放大和缩小内容页面?

c# - 我如何在字符串c#中获取某个索引之后的所有内容

ruby-on-rails - 发布文件时出现 Ruby 错误 RangeError

javascript - 有效的 JSON 文件可以仅包含一个对象的描述吗?

c# - 如何使用linq从表中获取最大id

c# - 如何正确处理System.Net.Mail.SmtpException?

javascript - JSon 和 Jquery Accordion

asp.net-mvc - 使用 ASP.NET MVC 中的内置 JsonResult 对 NHibernate 实体进行 JSON 序列化会产生循环依赖错误

java - 从 jPBC 保存和加载非对称 key

c# - 反序列化来自 Json Http 响应的对象列表