【发布时间】:2014-02-13 01:07:39
【问题描述】:
我正在处理一个Entity Framework 项目。我想序列化一堆实体类实例。我已经将它们绑定到一个容器类中:
public class Pseudocontext
{
public List<Widget> widgets;
public List<Thing> things;
等等...这是我试图序列化的此类的一个实例。我希望 JSON.NET 序列化每个实体类实例的成员,这些成员实际上是底层数据库中的列。我什至不希望它尝试序列化对象引用。
特别是,我的实体类具有虚拟成员,允许我编写 C# 代码来导航我所有的实体间关系,而无需担心实际的键值、连接等,并且我希望 JSON.NET 忽略关联的部分我的实体类。
从表面上看,似乎有一个 JSON.NET 配置选项完全符合我的意思:
JsonSerializer serializer = new JsonSerializer();
serializer.PreserveReferencesHandling = PreserveReferencesHandling.None;
不幸的是,JSON.NET 似乎忽略了上面的第二条语句。
我实际上发现了一个网页 (http://json.codeplex.com/workitem/24608),其他人在该网页上将同样的问题提请 James Newton-King 本人注意,他的回复(全部)是“编写自定义合同解析程序”。
尽管我发现这种反应不够充分,但我一直在尝试遵循它的指导。我非常希望能够编写一个“合同解析器”,它忽略除原始类型、字符串、DateTime 对象和我自己的 Pseudocontext 类以及它直接包含的列表之外的所有内容。如果有人有一个至少与此相似的例子,那可能就是我所需要的。这是我自己想出来的:
public class WhatDecadeIsItAgain : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
JsonContract contract = base.CreateContract(objectType);
if (objectType.IsPrimitive || objectType == typeof(DateTime) || objectType == typeof(string)
|| objectType == typeof(Pseudocontext) || objectType.Name.Contains("List"))
{
contract.Converter = base.CreateContract(objectType).Converter;
}
else
{
contract.Converter = myDefaultConverter;
}
return contract;
}
private static GeeThisSureTakesALotOfClassesConverter myDefaultConverter = new GeeThisSureTakesALotOfClassesConverter();
}
public class GeeThisSureTakesALotOfClassesConverter : Newtonsoft.Json.Converters.CustomCreationConverter<object>
{
public override object Create(Type objectType)
{
return null;
}
}
当我尝试使用上述方法时(通过在序列化之前将 serializer.ContractResolver 设置为 WhatDecadeIsItAgain 的实例),我在序列化期间收到 OutOfMemory 错误,表明 JSON.NET 遇到了永远不会终止的引用循环(尽管我努力使 JSON.NET忽略对象引用)。
我觉得我的“自定义合同解析器”可能有误。如上所示,它是围绕这样一个前提构建的,即我应该为我想要序列化的类型返回默认的“合同”,以及为所有其他类型简单地返回“null”的“合同”。
不过,我不知道这些假设有多正确,也很难说清楚。 JSON.NET 设计非常基于实现继承、方法覆盖等;我不是一个OOP 的人,我发现这种设计非常晦涩难懂。如果有我可以实现的“自定义合同解析器”接口,Visual Studio 2012 将能够非常快速地存根出所需的方法,而且我想用真实的逻辑填充存根不会有什么问题。
例如,如果我想序列化所提供类型的对象,则返回“true”,否则返回“false”,我可以毫无问题地编写。也许我遗漏了一些东西,但我没有发现这样的方法可以覆盖,也找不到假设的接口(ICustomContractResolver?),它可以告诉我在最后一个代码中我实际上应该做什么-p 在上面插入。
另外,我意识到有一些 JSON.NET 属性 ([JsonIgnore]?) 旨在处理此类情况。我不能真正使用这种方法,因为我使用的是“模型优先”。除非我决定拆除我的整个项目架构,否则我的实体类将自动生成,并且它们不会包含 JsonIgnore 属性,我也不愿意编辑自动化类以包含这些属性。
顺便说一句,有一段时间我确实设置了一些东西来序列化对象引用,我只是忽略了 JSON.NET 返回的所有多余的“$ref”和“$id”数据在其序列化输出中。我至少暂时放弃了这种方法,因为(相当突然)序列化开始花费过多的时间(大约 45 分钟才能获得大约 5 MB 的 JSON)。
我无法将性能的突然变化与我所做的任何具体事情联系起来。如果有的话,我的数据库中的数据量现在低于序列化在合理时间内实际完成时的数据量。但如果可以实现的话,我会非常高兴回到 status quo ante(我只需要忽略“$ref”、“$id”等) .
此时,我也对使用其他 JSON 库或完全不同的策略持开放态度。我觉得我可以只使用 StringBuilder、System.Reflection 等,并使用我自己的自制解决方案......但是 JSON.NET 不应该能够很容易地处理这种事情吗??
【问题讨论】:
标签: c# .net json serialization json.net