如何在不丢失其特定 属性 的情况下将子实例反序列化为父对象?
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;}
}
我看到了这个问题的多种解决方案,但它们不够优雅:
- 将 属性B 的类型作为对象:我失去了这个 属性 的强类型。
- 将有问题的部分重新序列化为子对象:这将很快变得丑陋
- 创建一个特定的 class ASerialisable(具有 B1 和 B2 属性),将字符串序列化为这个,然后使用构造函数从这个 class 创建一个 A 对象:和上面一样,如果类似的问题很多,恐怕会产生很多classes。
*在序列化之前添加对象的类型并使用属性 TypeNameHandling。我没有看到不涉及部分反序列化的方法。
类似的问题,但我也不是序列化字符串的人,所以我不能使用这个解决方案:
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
{
//...
}
下面是几个 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;}
}
我看到了这个问题的多种解决方案,但它们不够优雅:
- 将 属性B 的类型作为对象:我失去了这个 属性 的强类型。
- 将有问题的部分重新序列化为子对象:这将很快变得丑陋
- 创建一个特定的 class ASerialisable(具有 B1 和 B2 属性),将字符串序列化为这个,然后使用构造函数从这个 class 创建一个 A 对象:和上面一样,如果类似的问题很多,恐怕会产生很多classes。 *在序列化之前添加对象的类型并使用属性 TypeNameHandling。我没有看到不涉及部分反序列化的方法。
类似的问题,但我也不是序列化字符串的人,所以我不能使用这个解决方案: 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
{
//...
}