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