我花时间测试了@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
}
}
}