如何在不丢失其特定属性的情况下将子实例反序列化为父对象? [英] How can I deserialize a child instance as a parent object without losing its specific property?

查看:98
本文介绍了如何在不丢失其特定属性的情况下将子实例反序列化为父对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是几个类.如何序列化A实例的Json字符串,其中PropertyB包含SpecPropB1或SpecPropB2,以便那些属性保留在C#对象中?

Below are several classes. How can I serialize a Json string of an instance of A in which PropertyB contains either SpecPropB1 or SpecPropB2 so that those properties remains in the C# object?

public class A
{
  public B PropertyB {get;set;}
}

public class B
{
  public string GenProp {get;set;}
}

public class B1:B
{
  public string SpecPropB1 {get;set;}
}

public class B2:B
{
  public string SpecPropB2 {get;set;}
}

我看到了解决此问题的多种解决方案,但它们缺乏风度:

I see multiple solutions to this problem but they lack elegance:

  • 将propertyB的类型作为对象:我失去了此属性的强类型.
  • 将有问题的部分重新序列化为子对象:这将很快变得丑陋
  • 创建一个特定的类ASerialisable(具有B1和B2属性),将字符串序列化为此,然后使用构造函数从此类创建A对象:与上述相同,恐怕它将创建很多类中是否有很多类似的问题. *在序列化之前添加对象的类型,并使用属性TypeNameHandling.我看不到没有部分反序列化的方法.
  • Put the type of propertyB as object: I lose the strong typing for this property.
  • Redeserialize the problematic part as a child object: this will quickly become ugly
  • Create a specific class ASerialisable (which have B1 and B2 property), serialise the string to this, then use a constructor to create an A object from this class: same as above, I am afraid that it will create a lot of classes if there is a lot of similar problem. *Add the type of the object before serializing and use the property TypeNameHandling. I don't see a way of doing that that doesn't involve a partial deserialisation.

类似的问题,但是我也不是序列化字符串的人,所以我不能使用此解决方案: 反序列化为正确的子对象

Similar problem, but I am nor the one which serialize the string, so i can't use this solution: Deserialize into correct child objects

我制作了一个继承JSonConverter的新类,该类自动完成Falanwe建议的工作. 这是需要它的人的最终代码.

I make a new class inheriting JSonConverter which automatically do the job proposed by Falanwe. Here is the final code for those needing it.

private class BConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(A).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader,
        Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject item = JObject.Load(reader);
        if(objectType.IsSubclassOf(typeof(B)) || objectType == typeof(B))
        {
            if (item["SpecPropB1"] != null)
            {
                return new B1() 
                { 
                    GenProp = (string)item["GenProp"], 
                    SpecPropB1 = (string)item["SpecPropB1"] 
                };
            }
            else if (item["SpecPropB2"] != null)
            {
                return new B2()
                {
                    GenProp = (string)item["GenProp"],
                    SpecPropB2 = (string)item["SpecPropB2"]
                };
            }
            else
            {
                return new B()
                {
                    GenProp = (string)item["GenProp"]
                };
            }
        }
        else
        {
            return item.ToObject(objectType);
        }
    }

    public override void WriteJson(JsonWriter writer,
        object value, JsonSerializer serializer)
    {
        //not implemented here but needed if you want to deserialized data,
        // this can help you: http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization/
        throw new NotImplementedException();
    }
}

private class A
{

    public B PropertyB { get; set; }
}

[JsonConverter(typeof(BConverter))]
private class B
{
    public string GenProp { get; set; }
}

private class B1 : B
{
    public string SpecPropB1 { get; set; }
}

private class B2 : B
{
    public string SpecPropB2 { get; set; }
} 

推荐答案

如果仅在少数情况下出现这种情况,请序列化为同时具有这两个属性的DTO(数据传输对象)类.如果您不想创建新的命名类,也可以使用匿名类来为您完成工作

If the situation arises in only a few cases, do serialize into a DTO (Data Transfer Object) class that has both properties. If you don't want to bother creating a new named class, you can also use an anonymous class that will do the job for you

var myDto = JsonConvert.DeserializeAnonymousType(jsonString,
    new {
        PropertyB = new {
            GenProp ="",
            SpecPropB1 ="",
            SpecPropB2 = ""}
        });

如果案件到达的频率太高,也就是说,如果不确定要反序列化的json模式,则可以反序列化为JObject,然后查询是否存在字段.

If the case arrises too frequently, that is if you are unsure of the schema of the json you're deserializing, you can deserialize into a JObject, and then query if fields are present or not.

B b;
JObject o = JObject.Parse(jsonString);

// I need this variable to compile, but I won't use it.
JToken _;
if(o.TryGetValue("SpecPropB1", out _)
{
    b = o.ToObject<B1>();
}
else
{
//...
}

这篇关于如何在不丢失其特定属性的情况下将子实例反序列化为父对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆