Json.NET缓存类型的序列化信息吗? [英] Does Json.NET cache types' serialization information?

查看:67
本文介绍了Json.NET缓存类型的序列化信息吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在.NET世界中,当涉及对象序列化时,通常会在运行时检查对象的字段和属性.通常,使用反射进行此工作很慢,并且在处理大量对象时是不可取的.另一种方法是使用IL发射或构建表达式树,这些树提供了比反射显着提高的性能.后者是大多数现代库在处理序列化时选择的.但是,在运行时建立和发布IL会花费一些时间,并且只有将该信息缓存并重新用于相同类型的对象时,投资才可以收回.

In .NET world, when it comes to object serialization, it usually goes into inspecting the object's fields and properties at runtime. Using reflection for this job is usually slow and is undesirable when dealing with large sets of objects. The other way is using IL emit or building expression trees that provide significant performance gain over reflection. And the latter is most modern libraries pick when dealing with serialization. However building and emitting IL at runtime takes time, and the investment is only paid back if this information is cached and reused for objects of the same type.

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

When using Json.NET, it is not clear to me which method described above is used, and if the latter is indeed used, whether the caching is used.

例如,当我这样做时:

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

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

Does Json.NET build the Foo's member access info and cache to reuse it later?

推荐答案

Json.NET在其 IContractResolver DefaultContractResolver CamelCasePropertyNamesContractResolver .除非您指定自定义合同解析器,否则此信息将被缓存和重用.

Json.NET caches type serialization information inside its IContractResolver classes DefaultContractResolver and CamelCasePropertyNamesContractResolver. Unless you specify a custom contract resolver, this information is cached and reused.

对于DefaultContractResolver,每当应用程序未指定其自己的合同解析器时,Json.NET就会在内部维护一个全局静态实例.另一方面,CamelCasePropertyNamesContractResolver维护在所有实例之间共享的静态表. (我认为不一致是由遗留问题引起的;请参见此处以获取详细信息.)

For DefaultContractResolver a global static instance is maintained internally that Json.NET uses whenever the application does not specify its own contract resolver. CamelCasePropertyNamesContractResolver, on the other hand, maintains static tables that are shared across all instances. (I believe the inconsistency arises from legacy issues; see here for details.)

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

Both of these types are designed to be fully thread-safe so sharing between threads should not be a problem.

如果您选择制作自己的合同解析器,则仅当您缓存和重用合同解析器实例本身时,类型信息才会被缓存和重用.因此,Newtonsoft 推荐:

If you choose to make your own contract resolver, then type information will only be cached and reused if you cache and reuse the contract resolver instance itself. Thus, Newtonsoft recommends:

为了提高性能,您应该创建一个合同解析器,并在可能的情况下重用实例.解决合同的速度很慢,并且IContractResolver的实现通常会缓存合同.

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子类中的缓存的一种策略是使其构造函数受到保护或私有,并提供全局静态实例. (当然,这仅在解析器为无状态"且始终返回相同结果的情况下才适用.)例如,受

One strategy for guaranteeing caching in a subclass of DefaultContractResolver is to make its constructor be protected or private, and provide a global static instance. (Of course this is only appropriate if the resolver is "stateless" and will always return the same results.) E.g., inspired by this question, here's a pascal case to underscore contract resolver:

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

您将使用哪种方式:

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

(注意-通过引入 SnakeCaseNamingStrategy .仅作说明之用.)

(N.B. - the utility of this particular resolver has been reduced with the introduction of SnakeCaseNamingStrategy. It has been left only as an illustrative example.)

如果存在内存消耗问题,并且出于任何原因,您需要最小化缓存的合同永久占用的内存,则可以构建自己的DefaultContractResolver本地实例(或某些自定义子类),使用该序列化,然后立即删除对其的所有引用,例如:

If memory consumption is a problem and for whatever reason you need to minimize the memory permanently taken by cached contracts, you can construct your own local instance of DefaultContractResolver (or some custom subclass), serialize using that, and then immediately remove all references to it, e.g.:

public class JsonExtensions
{
    public static string SerializeObjectNoCache<T>(T obj, JsonSerializerSettings settings = null)
    {
        settings = settings ?? new JsonSerializerSettings();
        if (settings.ContractResolver == null)
            // To reduce memory footprint, do not cache contract information in the global contract resolver.
            settings.ContractResolver = new DefaultContractResolver();
        return JsonConvert.SerializeObject(obj, settings);
    }
}

大多数缓存的合约内存最终将被垃圾回收.当然,这样做可能会严重影响串行化性能

The majority of cached contract memory will eventually get garbage collected. Of course, by doing this, serialization performance may suffer substantially.

有关更多信息,请参阅Newtonsoft的性能提示:重用合同解析器.

For further information see Newtonsoft's Performance Tips: Reuse Contract Resolver.

这篇关于Json.NET缓存类型的序列化信息吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆