KFL*_*KFL 24 c# serialization json expression-trees json.net
在.NET世界中,当谈到对象序列化时,它通常用于在运行时检查对象的字段和属性.对此作业使用反射通常很慢,并且在处理大量对象时是不合需要的.另一种方法是使用IL发射或构建表达树,这些表现树相对于反射提供显着的性能增益.而后者是处理序列化时最现代化的库.但是,在运行时构建和发送IL需要花费时间,并且只有在将此信息缓存并重用于相同类型的对象时才会回收投资.
当使用Json.NET时,我不清楚使用上述哪种方法,如果确实使用了后者,是否使用了缓存.
例如,当我这样做时:
JsonConvert.SerializeObject(new Foo { value = 1 });
Run Code Online (Sandbox Code Playgroud)
Json.NET是否构建了Foo的成员访问信息并缓存以便以后重用它?
dbc*_*dbc 27
Json.NET缓存其内部类型的序列信息IContractResolver类DefaultContractResolver和CamelCasePropertyNamesContractResolver.除非您指定自定义合同解析程序,否则将缓存并重复使用此信息.
对于DefaultContractResolver全局静态实例,内部维护Json.NET在应用程序未指定自己的合同解析程序时使用. CamelCasePropertyNamesContractResolver另一方面,维护所有实例共享的静态表.(我认为这种不一致性来自遗留问题; 详情请见此处.)
这两种类型都设计为完全线程安全的,因此线程之间的共享应该不是问题.
如果您选择制作自己的合同解析程序,则只有在缓存并重用合同解析程序实例本身时,才会缓存并重用类型信息.因此,Newtonsoft 建议:
为了提高性能,您应该创建一次合同解析程序,并在可能的情况下重用实例.解决合同的速度很慢,IContractResolver的实现通常会缓存合同.
保证子类中缓存的一种策略DefaultContractResolver是使其构造函数受到保护或私有,并提供全局静态实例.(当然这只适用于解析器是"无状态"并且总会返回相同的结果.)例如,受这个问题的启发,这是一个强调合同解析器的pascal案例:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
您将使用哪个:
var json = JsonConvert.SerializeObject(someObject, new JsonSerializerSettings { ContractResolver = PascalCaseToUnderscoreContractResolver.Instance });
Run Code Online (Sandbox Code Playgroud)
(注意 - 这个特定的旋转变压器的效用随着引入而减少了SnakeCaseNamingStrategy.它只是作为一个说明性的例子.)
如果内存消耗是一个问题,无论出于何种原因,您需要最小化缓存合同永久占用的内存,您可以构建自己的本地实例DefaultContractResolver(或某个自定义子类),使用它进行序列化,然后立即删除对它的所有引用,例如:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
大多数缓存的合同内存最终都会被垃圾收集.当然,通过这样做,序列化性能可能会受到很大影响.
| 归档时间: |
|
| 查看次数: |
4832 次 |
| 最近记录: |