首先有一个类 包含接口集合 例如
public class ExtractBase
{
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty("selectors",ItemConverterType = typeof(ISelectorConverter))]
public List<ISelector> Selectors { get; set; }
public ExtractBase(string name = "")
{
Name = name;
Selectors = new List<ISelector>();
}
}
Selectors的类型是 List<ISelector>,序列化的结果可能如下
{
"tiles": {
"metas": {
"title": {
"name": "title",
"selectors": [{
"attr": null,
"type": 2,
"value": ".pt-cv-title",
"remove": 0,
"baseType": 0
}]
},
"url": {
"name": "url",
"selectors": [{
"attr": "href",
"type": 1,
"value": ".pt-cv-readmore",
"remove": 0,
"baseType": 0
}]
}
},
"name": "",
"selectors": [{
"attr": null,
"type": 0,
"value": ".pt-cv-content-item",
"remove": 0,
"baseType": 0
}]
},
"blocks": [],
"metas": {},
"name": "",
"selectors": [{
"attr": null,
"type": 0,
"value": ".entry-content",
"remove": 0,
"baseType": 0
}]
}
序列化的json数据,在反序列化的时候会报找不到selectors的反序列话实例的错误
有两种方法可以解决这个问题
1. 使用JsonSerializerSettings 序列化的时候把$type带上
var setting = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects
};
var json = JsonConvert.SerializeObject(request, setting);
这样结果会包含反序列化需要的类型信息
反序列化时这样既可
var setting = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects
};
var request = JsonConvert.DeserializeObject<ExtractRequest>(json, setting);
但是由于json里面带了反序列化需要的类型信息,整个json文件显得比较大
{
"$type": "RuiJi.Core.Extracter.ExtractBlock, RuiJi.Core",
"tiles": {
"$type": "RuiJi.Core.Extracter.ExtractTile, RuiJi.Core",
"metas": {
"$type": "RuiJi.Core.Extracter.ExtractMetaCollection, RuiJi.Core",
"title": {
"$type": "RuiJi.Core.Extracter.ExtractBase, RuiJi.Core",
"name": "title",
"selectors": [{
"$type": "RuiJi.Core.Extracter.Selector.CssSelector, RuiJi.Core",
"attr": null,
"type": 2,
"value": ".pt-cv-title",
"remove": 0,
"baseType": 0
}]
},
"url": {
"$type": "RuiJi.Core.Extracter.ExtractBase, RuiJi.Core",
"name": "url",
"selectors": [{
"$type": "RuiJi.Core.Extracter.Selector.CssSelector, RuiJi.Core",
"attr": "href",
"type": 1,
"value": ".pt-cv-readmore",
"remove": 0,
"baseType": 0
}]
}
},
"name": "",
"selectors": [{
"$type": "RuiJi.Core.Extracter.Selector.CssSelector, RuiJi.Core",
"attr": null,
"type": 0,
"value": ".pt-cv-content-item",
"remove": 0,
"baseType": 0
}]
},
"blocks": [],
"metas": {
"$type": "RuiJi.Core.Extracter.ExtractMetaCollection, RuiJi.Core"
},
"name": "",
"selectors": [{
"$type": "RuiJi.Core.Extracter.Selector.CssSelector, RuiJi.Core",
"attr": null,
"type": 0,
"value": ".entry-content",
"remove": 0,
"baseType": 0
}]
}
2. 为接口类增加一个类型枚举
public interface ISelector
{
SelectorTypeEnum SelectorType { get; }
RemoveEnum Remove { get; set; }
string Value { get; set; }
}
public abstract class SelectorBase : ISelector
{
[JsonProperty("value")]
public string Value { get; set; }
[JsonProperty("remove")]
public RemoveEnum Remove { get; set; }
[JsonProperty("baseType")]
public SelectorTypeEnum SelectorType { get; private set; }
protected abstract SelectorTypeEnum SetSelectType();
public SelectorBase()
{
SelectorType = SetSelectType();
}
}
实例序列化结果
"selectors": [{
"attr": null,
"type": 2,
"value": ".pt-cv-title",
"remove": 0,
"baseType": 0
}]
反序列化时 你需要这样 告诉Json.Net 集合项转换类型
[JsonProperty("selectors",ItemConverterType = typeof(ISelectorConverter))]
public List<ISelector> Selectors { get; set; }
IselectorConverter 如下
[JsonArray]
public class ISelectorConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType is ISelector;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jsonObject = JObject.Load(reader);
var type = jsonObject.SelectToken("baseType").ToString();
var json = jsonObject.ToString();
switch(type)
{
case "0":
{
return JsonConvert.DeserializeObject<CssSelector>(json);
}
case "1":
{
return JsonConvert.DeserializeObject<RegexSelector>(json);
}
case "2":
{
return JsonConvert.DeserializeObject<RegexSplitSelector>(json);
}
case "3":
{
return JsonConvert.DeserializeObject<TextRangeSelector>(json);
}
case "4":
{
return JsonConvert.DeserializeObject<ExcludeSelector>(json);
}
case "5":
{
return null;
}
case "6":
{
return JsonConvert.DeserializeObject<JsonPathSelector>(json);
}
case "7":
{
return JsonConvert.DeserializeObject<XPathSelector>(json);
}
case "8":
{
return JsonConvert.DeserializeObject<ClearTagSelector>(json);
}
}
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
虽然Converter写的比较麻烦,但是序列化的json还是比较小的