我正在开发一个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的设计非常基于实现继承、方法重写等;我不是一个面向对象编程的人,我觉得这种设计相当晦涩难懂。如果有一个“自定义合同解析器”接口,我就可以实现它,Visual Studio 2012就能很快地生成所需的方法存根,我想我填充这些存根以实现真正的逻辑也不会有太大的问题。
举个例子,我可以轻松地编写一个方法,如果要序列化一个指定类型的对象,则返回“true”,否则返回“false”。也许我漏掉了什么,但我没有找到任何需要重写的方法,也没有找到假设接口(ICustomContractResolver?)告诉我上述代码片段中我应该做什么。
此外,我意识到有些 JSON.NET 属性([JsonIgnore]?)是专门设计用来处理这种情况的。但是我无法使用该方法,因为我正在使用“模型优先”的方法。除非我决定彻底重构整个项目架构,否则实体类将自动生成,它们不会包含 JsonIgnore 属性,也不会在编辑自动化类时感到舒适。顺便说一句,有一段时间,我设置了对象引用序列化,并且只忽略了所有超额的“$ref”和“$id”数据,而 JSON.NET 在其序列化输出中返回了这些数据。至少目前,我已经放弃了这种方法,因为(相当突然地)序列化开始花费很多时间(大约 45 分钟才能获取约 5 MB 的 JSON)。
我无法将这种性能的突然变化与我所做的任何具体事情联系起来。如果说有什么区别的话,我的数据库中的数据量现在比序列化所需的合理时间要少。但如果能够实现返回到以前的状态(其中我只需要忽略“$ref”、“$id”等内容),那我将非常高兴。
目前,我也愿意考虑使用其他的JSON库,或者完全不同的策略。我感觉我可以使用StringBuilder、System.Reflection等来自己制定一个解决方案...但是JSON.NET不应该能够轻松处理这种情况吗?