我试图扩展这里给出的JSON.net示例http://james.newtonking.com/projects/json/help/CustomCreationConverter.html
我有另一个派生自基类/接口的子类
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Employee : Person
{
public string Department { get; set; }
public string JobTitle { get; set; }
}
public class Artist : Person
{
public string Skill { get; set; }
}
List<Person> people = new List<Person>
{
new Employee(),
new Employee(),
new Artist(),
};
如何将Json反序列化回List <Person>
[
{
"Department": "Department1",
"JobTitle": "JobTitle1",
"FirstName": "FirstName1",
"LastName": "LastName1"
},
{
"Department": "Department2",
"JobTitle": "JobTitle2",
"FirstName": "FirstName2",
"LastName": "LastName2"
},
{
"Skill": "Painter",
"FirstName": "FirstName3",
"LastName": "LastName3"
}
]
我不想使用TypeNameHandling JsonSerializerSettings . 我特意寻找自定义JsonConverter实现来处理这个问题 . 网络上的文档和示例非常稀少 . 我似乎无法在JsonConverter中获得重写的ReadJson()方法实现 .
8 回答
使用标准
CustomCreationConverter
,我正在努力工作如何生成正确的类型(Person
或Employee
),因为为了确定这一点,您需要分析JSON,并且没有内置的方法来使用Create
方法执行此操作 .我找到了一个与类型转换有关的讨论主题,结果却提供了答案 . 这是一个链接:Type converting .
所需要的是子类
JsonConverter
,重写ReadJson
方法并创建一个接受JObject
的新抽象Create
方法 .重写的
ReadJson
方法创建JObject
并调用Create
方法(由我们派生的转换器类实现),传入JObject
实例 .然后可以通过检查某些字段的存在来分析该
JObject
实例以确定正确的类型 .Example
以上针对
JsonCreationConverter<T>
的解决方案遍布互联网,但有一个缺陷在极少数情况下表现出来 . 在ReadJson方法中创建的新JsonReader不会继承任何原始读者的配置值(Culture,DateParseHandling,DateTimeZoneHandling,FloatParseHandling等等) . 在serializer.Populate()中使用新的JsonReader之前,应复制这些值 .这是我能解决上述实现中的一些问题的最好方法,但我仍然认为有些事情被忽略了:
Update 我对此进行了更新,以便有一个更明确的方法来制作现有阅读器的副本 . 这只是封装了复制单个JsonReader设置的过程 . 理想情况下,此功能将在Newtonsoft库本身中维护,但是现在,您可以使用以下内容:
这应该如下使用:
Older solution follows:
只是想我会分享一个基于此的解决方案,使用反射的Knowntype属性,必须从任何基类获取派生类,解决方案可以受益于递归找到最佳匹配类虽然我不需要它在我的例如,匹配是通过给转换器的类型完成的,如果它具有KnownTypes,它将扫描所有类型,直到它匹配具有json字符串内所有属性的类型,首先选择要匹配的类型 .
用法很简单:
在上述情况下,ret将是B型 .
JSON类:
转换器代码:
这是对图腾答案的扩展 . 它基本上做了同样的事情,但属性匹配基于序列化的json对象,而不是反映.net对象 . 如果你使用[JsonProperty],使用CamelCasePropertyNamesContractResolver,或者做任何会导致json与.net对象不匹配的事情,这一点很重要 .
用法很简单:
转换器代码:
作为Totem已知类型解决方案的另一种变体,您可以使用反射创建泛型类型解析器,以避免使用已知类型属性 .
这对于WCF使用类似于Juval Lowy's GenericResolver的技术 .
只要您的基类是抽象的或接口,就会自动确定已知类型,而不必使用已知类型属性进行修饰 .
在我自己的情况下,我选择使用$ type属性来指定我的json对象中的类型,而不是尝试从属性中确定它,尽管您可以从这里借用其他解决方案来使用基于属性的确定 .
然后可以将其安装为格式化程序
项目JsonSubTypes实现了一个通用转换器,可以通过属性帮助处理此功能 .
对于这里提供的具体样本是如何工作的:
这是另一个避免使用
jObject.CreateReader()
的解决方案,而是创建一个新的JsonTextReader
(这是默认JsonCreate.Deserialze
方法使用的行为:很多时候,实现将存在于与接口相同的命名空间中 . 所以,我想出了这个:
因此,您可以像这样全局包含: