使用JsonConvert.DeserializeObject反序列化一个派生对象列表

4
我有这个对象。
public class ConversationAPI
{
    [JsonProperty(PropertyName = "lU")]
    public DateTime LastUpdated { get; set; }

    [JsonProperty(PropertyName = "m", TypeNameHandling = TypeNameHandling.All)]
    public List<Message> Messages { get; set; }
}

我从API中发送的内容为json格式,客户端应用程序将其反序列化。

The List<Message> Messages property contains either 

 [Serializable]
    public class Message
    {
        [JsonProperty(PropertyName = "t")]
        public string Text { get; set; }

        [JsonProperty(PropertyName = "ty")]
        public MessageType Type { get; set; }
    }

或者

[Serializable]
    public class DerivedMessage : Message
    {
        [JsonProperty(PropertyName = "sos")]
        public string SomeOtherStuff{ get; set; }
    }

我似乎无法对派生类型的数组进行反序列化。 我尝试了以下方法

var settings = new JsonSerializerSettings
                    {
                        TypeNameHandling = TypeNameHandling.All,
                        TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
                    };
var conversation = JsonConvert.DeserializeObject<ConversationResponse>(response.Content, settings);

我希望List Messages包含MessageDerivedMessage对象。
有什么想法吗? 谢谢。
2个回答

6
找到了解决方案。我使用了自定义转换器。
public class MessageConverter : JsonCreationConverter<ConversationAPI.Message>
{
    private const string SomeOtherStuffField = "sos";

    protected override ConversationAPI.Message Create(Type objectType, JObject jObject)
    {
        if (FieldExists(SomeOtherStuffField , jObject))
        {
            return new ConversationAPI.DerivedMessage ();
        }

        return new ConversationAPI.Message();
    }

    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 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;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

您可以这样使用它:
var jsonText = "{a string of json to convert}"
JsonConverter[] conv = new JsonConverter[] { new MessageConverter() };
var jsonResponse = JsonConvert.DeserializeObject<ConversationAPI>(jsonText, conv);

感谢您发布解决方案。做得好。 - CodeChops
很高兴它对其他人也有用 :) - Mihai
我编写了一个自定义转换器,可以将许多变量序列化或反序列化为true或false(例如1和0或T和F)。我喜欢newtonsoft,所以我对你的问题很感兴趣,但是在我能够提供解决方案之前,你已经回答了它!:P - CodeChops

0

我花时间测试了@Mihai发布的代码。我喜欢这个解决方案,因为它不会改变json文件的内容;序列化与平常一样(没有添加$type或其他属性)。反序列化通过检查json中是否存在派生字段来确定对象是基类还是派生类。虽然这不是万无一失的,但在大多数情况下都能很好地工作。

我不得不修复一些语法错误才能让它运行并理解它的工作原理。 以下是修改后的代码和一个可工作的使用示例:

using System;
using System.Collections.Generic;
using System.IO;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace DerivedDeSerJson
{
    [Serializable]
    public class Message
    {
        public string Text { get; set; }
    }

    [Serializable]
    public class DerivedMessage : Message
    {
        public string SomeOtherStuff { get; set; }
    }

    public class ConversationAPI
    {
        public DateTime LastUpdated { get; set; }

        public List<Message> Messages { get; set; }
    }

    public class MessageConverter : JsonCreationConverter<Message>
    {
        private const string SomeOtherStuffField = "SomeOtherStuff";

        protected override Message Create(Type objectType, JObject jObject)
        {
            if (FieldExists(SomeOtherStuffField, jObject))
            {
                return new DerivedMessage();
            }

            return new Message();
        }

        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 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;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ConversationAPI conversation = new ConversationAPI()
            {
                LastUpdated = DateTime.Now,
                Messages = new List<Message>()
                {
                   new Message() {Text = "Msg1"},
                   new DerivedMessage() {Text = "Msg2", SomeOtherStuff = "stuff"},
                }
            };
            string jsonText;
            JsonSerializer serializer = new JsonSerializer() { Formatting = Formatting.Indented };
            using (TextWriter text = new StringWriter())
            using (JsonWriter writer = new JsonTextWriter(text))
            {
                serializer.Serialize(writer, conversation);
                jsonText = text.ToString();
            }
            Console.WriteLine(jsonText);
            //Output:
            //{
            //    "LastUpdated": "2020-06-08T17:05:33.7114095+03:00",
            //    "Messages": 
            //    [
            //        { "Text": "Msg1" },
            //        { "SomeOtherStuff": "stuff", "Text": "Msg2" }
            //    ]
            //}

            JsonConverter[] conv = new JsonConverter[] { new MessageConverter() };
            ConversationAPI jsonResponse = JsonConvert.DeserializeObject<ConversationAPI>(jsonText, conv);

            foreach (var msg in jsonResponse.Messages)
            {
                Console.WriteLine(msg.Text);
                Console.WriteLine(msg.ToString());      // Print type name
            }
            //Output:
            // Msg1
            // DerivedDeSerJson.Message
            // Msg2
            // DerivedDeSerJson.DerivedMessage
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接