如何在不丢失其特定 属性 的情况下将子实例反序列化为父对象?

How can I deserialize a child instance as a parent object without losing its specific property?

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

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

我看到了这个问题的多种解决方案,但它们不够优雅:

类似的问题,但我也不是序列化字符串的人,所以我不能使用这个解决方案: Deserialize into correct child objects

编辑:

我做了一个新的 class 继承 JSonConverter 自动完成 Falanwe 提出的工作。 这是为需要它的人提供的最终代码。

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(数据传输对象)class。如果您不想创建一个新的命名 class,您也可以使用一个匿名的 class 来完成这项工作

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

如果这种情况出现得太频繁,也就是说,如果您不确定要反序列化的 json 的架构,您可以反序列化为 JObject,然后查询字段是否存在。

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
{
//...
}