I am trying to extend the JSON.net example given here http://james.newtonking.com/projects/json/help/CustomCreationConverter.html

I have another sub class deriving from base class/Interface

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

How do I deserialize following Json back to List< Person >

[
  {
    "Department": "Department1",
    "JobTitle": "JobTitle1",
    "FirstName": "FirstName1",
    "LastName": "LastName1"
  },
  {
    "Department": "Department2",
    "JobTitle": "JobTitle2",
    "FirstName": "FirstName2",
    "LastName": "LastName2"
  },
  {
    "Skill": "Painter",
    "FirstName": "FirstName3",
    "LastName": "LastName3"
  }
]

I don't want to use TypeNameHandling JsonSerializerSettings. I am specifically looking for custom JsonConverter implementation to handle this. The documentation and examples around this are pretty sparse on the net. I can't seem to get the the overridden ReadJson() method implementation in JsonConverter right.

推荐答案

使用标准CustomCreationConverter时,我正在努力研究如何生成正确的类型(PersonEmployee),因为为了确定这一点,您需要分析JSON,而使用Create方法没有内置的方法来实现这一点.

我找到了一条关于类型转换的讨论线索,结果它提供了答案.这里有一个链接:Type converting (archived link).

所需的是子类JsonConverter,重写ReadJson方法并创建一个新的抽象Create方法,该方法接受JObject.

JObject类提供了加载JSON对象和

The overridden ReadJson method creates a JObject and invokes the Create method (implemented by our derived converter class), passing in the JObject instance.

然后可以通过判断某些字段的存在来分析这JObject个实例,以确定正确的类型.

Example

string json = "[{
        \"Department\": \"Department1\",
        \"JobTitle\": \"JobTitle1\",
        \"FirstName\": \"FirstName1\",
        \"LastName\": \"LastName1\"
    },{
        \"Department\": \"Department2\",
        \"JobTitle\": \"JobTitle2\",
        \"FirstName\": \"FirstName2\",
        \"LastName\": \"LastName2\"
    },
        {\"Skill\": \"Painter\",
        \"FirstName\": \"FirstName3\",
        \"LastName\": \"LastName3\"
    }]";

List<Person> persons = 
    JsonConvert.DeserializeObject<List<Person>>(json, new PersonConverter());

...

public class PersonConverter : JsonCreationConverter<Person>
{
    protected override Person Create(Type objectType, JObject jObject)
    {
        if (FieldExists("Skill", jObject))
        {
            return new Artist();
        }
        else if (FieldExists("Department", jObject))
        {
            return new Employee();
        }
        else
        {
            return new Person();
        }
    }

    private bool FieldExists(string fieldName, JObject jObject)
    {
        return jObject[fieldName] != null;
    }
}

public abstract class JsonCreationConverter<T> : JsonConverter
{
    /// <summary>
    /// Create an instance of objectType, based properties in the JSON object
    /// </summary>
    /// <param name="objectType">type of object expected</param>
    /// <param name="jObject">
    /// contents of JSON object that will be deserialized
    /// </param>
    /// <returns></returns>
    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, 
                                    Type objectType, 
                                     object existingValue, 
                                     JsonSerializer serializer)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}

Json相关问答推荐

使用jq解析多层json

从先前的REST调用创建动态JSON主体

如何创建可由Gin序列化到json的排序键值映射?

处理输入数据并转换为更简单的格式-PowerBI

无法从JSON解析ZonedDateTime,但可以使用格式化程序很好地解析

基于 JSON 字段的 Jolt 条件标志

Jolt 转换数组对象并将某些字段移动到嵌套数组

VBA-JSON 嵌套集合解析为 Excel

修改 boost::json::object 中的值

PowerShell - 如何迭代 PSCustomObject 嵌套对象?

Google GCM 服务器返回未经授权的错误 401

使用 c# 通用地展平 Json

十六进制格式可以与 JSON 文件一起使用吗?如果是这样,怎么做?

在 JSON 对象中强制执行非空字段

Select 什么数据类型json或者jsonb或者text

Spring Security 和 JSON 身份验证

alert Json 对象

JSON JQ 如果没有 else

JSON 和 BSON 哪个更轻量级?

如何从 jQuery ajax 调用将复杂对象传递给 ASP.NET WebApi GET?