反序列化具有 2 种类型字段且一种类型是递归的 Json
Posted
技术标签:
【中文标题】反序列化具有 2 种类型字段且一种类型是递归的 Json【英文标题】:Deserialize a Json with a field being of 2 types and one type is recursive 【发布时间】:2021-01-21 10:05:31 【问题描述】:有一个我从中得到 json 结果的 typescript 部分,需要在 c# 中解析结果以获取使用它的对象,但是因为我们在这里:
-
多类型字段
递归
越来越难以理解反序列化器的外观, 我知道我需要将 JsonConverter 用于多类型字段,但是如何处理沿多类型字段的递归?
这是制作 json 的打字稿代码:
export interface FilterDescriptor
field ? : string | Function;
operator: string | Function;
value ? : any;
ignoreCase ? : boolean;
export interface CompositeFilterDescriptor
logic: 'or' | 'and';
filters: Array < FilterDescriptor | CompositeFilterDescriptor > ;
export declare
const isCompositeFilterDescriptor: (source: FilterDescriptor | CompositeFilterDescriptor) => source is CompositeFilterDescriptor;
json 的一个例子: 递归
"logic": "and",
"filters": [
"field": "type.group",
"logic": "and",
"filters": [
"field": "type.group",
"operator": "neq",
"value": 2
,
"field": "type.group",
"operator": "neq",
"value": 5
]
]
没有递归:
"logic": "and",
"filters": [
"field": "type.group",
"operator": "eq",
"value": 2
]
这个 json 是使用来自 Telerik "CompositeFilterDescriptor" 的 Kendo Ui for Angular 生成的
谢谢。
【问题讨论】:
值字段是number
吗?
它也可以是一个字符串,甚至是一个像“2,4,5”这样的数组
嗯.. 它更复杂。
sidequestion:这是您的递归示例,最大递归数还是更多?
理论上可以有好几层,我的只有2层。
【参考方案1】:
问题在于 C# 没有“可区分联合”构造的等价物(至少,我认为这就是所谓的 ;-))
可用于多态性的唯一构造是接口和继承。
在这种情况下,您需要两种类型(FilterDescriptor
和CompositeFilterDescriptor
),并且需要多态性,因为CompositeFilterDescriptor
有一个可以包含其中任何一种的数组。在 C# 中,您需要一个接口或基类来表达:
interface IFilterDescriptor
class FilterDescriptor : IFilterDescriptor
// ... (fields of FilterDescriptor)
class CompositeFilterDescriptor : IFilterDescriptor
public string @logic get; set;
public IFilterDescriptor[] filters get; set;
此外,您不能使用 Json.NET 默认反序列化,因为多态反序列化需要类型信息。但是,您可以创建一个自定义转换器,您可以在其中检查某些字段的存在以确定如何反序列化对象:
public class FilterDescriptorConverter : JsonConverter
public override bool CanConvert(Type objectType) => typeof(IFilterDescriptor).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
JObject o = JObject.Load(reader);
// if the 'logic' field is present, it's a CompositeFilter
var item = o["logic"] != null
? (IFilterDescriptor)new CompositeFilterDescriptor()
: (IFilterDescriptor)new FilterDescriptor();
serializer.Populate(o.CreateReader(), item);
return item;
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
你可以这样使用它:
var result = JsonConvert.DeserializeObject<IFilterDescriptor>(json,
new FilterDescriptorConverter());
【讨论】:
以上是关于反序列化具有 2 种类型字段且一种类型是递归的 Json的主要内容,如果未能解决你的问题,请参考以下文章