Json.net 序列化/反序列化 abstract class

System.Text.Json 的解決方法:System.Text.Json 序列/反序列化 abstract class

用于檢測類型的枚舉

    public enum ItemTypes
    {
        Unknow = 0,
        Name,
        EnName,
        Mobile,
。。。

抽象類定義:

    [JsonConverter(typeof(RequirementConverter))]
    [Newtonsoft.Json.JsonConverter(typeof(RequirementConvertJsonNet))]
    public abstract class BaseItem
    {
        public virtual string ItemName { get; set; }

        public bool IsRequired { get; set; }

        public abstract ItemTypes Type { get; }

        public string Value { get; set; }
    }

子類定義:

    public class AddressItem : BaseItem
    {
        public override string ItemName { get; set; } = "地址";

        public override ItemTypes Type => ItemTypes.Address;
    }

用于檢查類型的臨時類:

        private class TypeDetectItem
        {
            [JsonProperty("Type")]
            public ItemTypes _Type { get; set; }

            [JsonIgnore]
            public ItemTypes Type => this._Type;
        }

ContractResolver 定義:

        private class BaseItemContractReslover : DefaultContractResolver
        {
            protected override JsonConverter ResolveContractConverter(Type objectType)
            {
                //因為 BaseItem 上指定了 Converter,
                //如果這里不返回 null 的話, 會一直循環執行, 導致 stackoverflow 異常.
                if (typeof(BaseItem).IsAssignableFrom(objectType) && !objectType.IsAbstract)
                    return null;
                return base.ResolveContractConverter(objectType);
            }
        }

Converter 定義:

   public class RequirementConvertJsonNet : JsonConverter<BaseItem>
    {
        private static readonly JsonSerializerSettings setting = new JsonSerializerSettings()
        {
            ContractResolver = new BaseItemContractReslover()
        };

        public override BaseItem ReadJson(JsonReader reader, Type objectType, BaseItem existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            var jobj = JObject.ReadFrom(reader);
            var detect = jobj.ToObject<TypeDetectItem>();

            var json = jobj.ToString();

            BaseItem o = detect.Type switch
            {
                ItemTypes.Name => JsonConvert.DeserializeObject<NameItem>(json, setting),
                ItemTypes.Credentials => JsonConvert.DeserializeObject<CredentialsItem>(json, setting),
                ItemTypes.Address => JsonConvert.DeserializeObject<AddressItem>(json, setting),
...
...
                _ => throw new NotImplementedException(),
            };

            return o;
        }

        public override void WriteJson(JsonWriter writer, BaseItem value, JsonSerializer serializer)
        {
            //這樣寫會報:Self referencing loop detected with type xxx
            //serializer.Serialize(writer, value, value?.GetType() ?? typeof(object));
            var json = JsonConvert.SerializeObject(value, value?.GetType() ?? typeof(object), setting);
            //writer.WriteRaw 會缺少逗號, writer.WriteValue 會把引號加上反斜杠。
            writer.WriteRawValue(json);
        }
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容