覆盖asp.net核心Newtonsoft.Json,以便能够处理继承

时间:2017-11-27 11:42:52

标签: c# json.net deserialization

考虑下一个代码段:

    static void Main(string[] args)
    {
        var classes = new Classes()
        {
            Instances = new A[]{
                new B
                {
                    BirthDate = DateTime.Now,
                    Name = "B1",
                    SomethingElse = "Test"
                },
                new C
                {
                    Name = "C1",
                    SomethingElse1 = "Test2",
                    SomethingElse2 = "Test3",
                }
            }
        };
        var serialized = JsonConvert.SerializeObject(classes);
        var deserialized = JsonConvert.DeserializeObject<Classes>(serialized);
    }
}

public class Classes
{
    public A[] Instances { get; set; }
}

public enum ClassType
{
    B = 1,
    C = 2
}

public class A
{
    public string Name { get; set; }
    public virtual ClassType ClassType { get; }
}

public class B : A
{
    public string SomethingElse { get; set; }
    public DateTime BirthDate { get; set; }
    public override ClassType ClassType => ClassType.B;

}

public class C : A
{
    public string SomethingElse1 { get; set; }
    public string SomethingElse2 { get; set; }
    public override ClassType ClassType => ClassType.C;
}

我需要将自己的逻辑注入到反序列化器如何处理具有继承的类的过程中。在这种情况下,我想根据JSON中的ClassType属性做出决定。任何想法/提示如何做到这一点?

顺便说一句。我知道我可以使用newtonsoft.json TypeNameHandling = TypeNameHandling.All的功能,但是我无法控制序列化过程,因为数据是从第三方系统发送的。我唯一能控制的是反序列化部分。

2 个答案:

答案 0 :(得分:1)

由于您无法使用TypeNameHandling,因此您必须先解析它,找到类型,然后反序列化。

像这样:

var jObj = Newtonsoft.Json.Linq.JObject.Parse(serialized);

var instances = jObj["Instances"].AsJEnumerable();
var myCol = new List<A>();
myCol.AddRange(instances.Select(x => (x["ClassType"] as JToken)
.ToObject<ClassType>() == ClassType.B ?
  (x as JObject).ToObject<B>() : 
  (x as JObject).ToObject<C>());

答案 1 :(得分:0)

感谢@zaitsman和@DavidG,我想出了适合我的解决方案。这是:

public class AClassConverter : JsonConverter
{
    private readonly Type[] _types;

    public AClassConverter(params Type[] types)
    {
        _types = types;
    }

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var jObj = JObject.Load(reader);
        var classType = jObj["ClassType"].ToObject<ClassType>();
        return classType == ClassType.B ? 
            (A)jObj.ToObject<B>() : 
            (A)jObj.ToObject<C>();
    }

    public override bool CanRead => true;

    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType)
    {
        return _types.Any(t => t == objectType);
    }
}

在反序列化时:

var deserialized = JsonConvert.DeserializeObject<Classes>(serialized, new AClassConverter(typeof(A)));