在容器类中具有子类型信息存在问题,原因有两个:
- 当Json.NET读取包含的类时,无法访问容器类实例。
- 如果以后需要将
SubTypeClassbase
属性转换为列表,则将无处放置子类型信息。
相反,我建议将子类型信息作为属性添加到基类中:
[JsonConverter(typeof(SubTypeClassConverter))]public class SubTypeClassbase{ [JsonConverter(typeof(StringEnumConverter))] // Serialize enums by name rather than numerical value public SubType Type { get { return typeToSubType[GetType()]; } }}现在,每当可分配给其的对象被序列化时,自定义子类型枚举都将被序列
SubTypeClassbase化。完成此操作后,对于反序列化,您可以创建一个
JsonConverter将给定的json加载
SubTypeClassbase到临时库中
JObject,检查
"Type"属性值,并将JSON对象反序列化为适当的类。
原型实现如下:
public enum SubType{ baseType, Type1, Type2,}[JsonConverter(typeof(SubTypeClassConverter))]public class SubTypeClassbase{ static readonly Dictionary<Type, SubType> typeToSubType; static readonly Dictionary<SubType, Type> subTypeToType; static SubTypeClassbase() { typeToSubType = new Dictionary<Type,SubType>() { { typeof(SubTypeClassbase), SubType.baseType }, { typeof(SubTypeClass1), SubType.Type1 }, { typeof(SubTypeClass2), SubType.Type2 }, }; subTypeToType = typeToSubType.ToDictionary(pair => pair.Value, pair => pair.Key); } public static Type GetType(SubType subType) { return subTypeToType[subType]; } [JsonConverter(typeof(StringEnumConverter))] // Serialize enums by name rather than numerical value public SubType Type { get { return typeToSubType[GetType()]; } }}public class SubTypeClass1 : SubTypeClassbase{ public string AaaField { get; set; }}public class SubTypeClass2 : SubTypeClassbase{ public string ZzzField { get; set; }}public class SubTypeClassConverter : JsonConverter{ public override bool CanConvert(Type objectType) { return objectType == typeof(SubTypeClassbase); } public override bool CanWrite { get { return false; } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); var typeToken = token["Type"]; if (typeToken == null) throw new InvalidOperationException("invalid object"); var actualType = SubTypeClassbase.GetType(typeToken.ToObject<SubType>(serializer)); if (existingValue == null || existingValue.GetType() != actualType) { var contract = serializer.ContractResolver.ResolveContract(actualType); existingValue = contract.DefaultCreator(); } using (var subReader = token.CreateReader()) { // Using "populate" avoids infinite recursion. serializer.Populate(subReader, existingValue); } return existingValue; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }}


