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
{
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();
var json = jobj.ToString();
BaseItem o = detect.Type switch
{
ItemTypes.Name => JsonConvert.DeserializeObject(json, setting),
ItemTypes.Credentials => JsonConvert.DeserializeObject(json, setting),
ItemTypes.Address => JsonConvert.DeserializeObject(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);
}