将 JSON 反序列化为具有抽象和非抽象类的对象



我想将以下JSON反序列化为我的C#树对象。无法编辑树结构。 杰森:

{
"Root": {
"Type": 0,
"children": [
{
"Type": 1,
"Name": " SERVICES",
"children": [
{
"Type": 2,
"Name": " SERVICES",
"Code": "S01",
"children": [],
"leaves": [
{
"Type": 6,
"Code": "H-L-CWP-50",
"Uom": "SQM",
"Measurements": "SQM",
"BaseRate": "€20"
},
{
"Type": 6,
"Code": "HMS-REM-001-03",
"Uom": "SQ.M",
"Measurements": "SQ.M",
"BaseRate": "€6.38"
}
]
}
]
}
]
}
}

C# 树:

public class Tree
{
public Root Root { get; set; }
public Tree()
{}
}
public class Root : Node
{
public override NodeType Type => NodeType.Root;
}
public class Group : Node
{
public override NodeType Type => NodeType.Group;
}
public class Category : Node
{
public override NodeType Type => NodeType.Category;
}
public class Type : Node
{
public override NodeType Type => NodeType.Type;
}
public class SubType : Node
{
public override NodeType Type => NodeType.SubType;
}
public class SubSubType : Node
{
public override NodeType Type => NodeType.SubsubType;
}
}
public abstract class Node
{
public int? ID { get; set; }
public int? FK { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public List<Node> children { get; set; }
public List<Item> leaves { get; set; }
}
public class Item
{
public string Code { get; set; }
public string Desc { get; set; }
public string Uom { get; set; }
public float? Measurements { get; set; }
public int? FK { get; set; }
}

树的设计方式是,节点可以具有其他节点的列表以及项目列表;分别在 JSON 中具有子项和叶子项列表。

使用我构建的自定义转换器,我可以在不存在叶子时反序列化节点,但填充的叶子使 JSON 无法识别并引发异常。

public class NodeConverter : JsonCreationConverter<Node> //notice the Node type here where in fact its a mixture of Nodes and Items.
{
protected override Node Create(Type objectType, JObject jObject)
{
switch ((Node.NodeType)jObject["Type"].Value<int>())
{
case Node.NodeType.Root:
return new Root();
case Node.NodeType.Group:
return new Group();
case Node.NodeType.Category:
return new Category();
case Node.NodeType.Type:
return new Type();
case Node.NodeType.SubType:
return new SubType();
case Node.NodeType.SubsubType:
return new SubSubType();
case Node.NodeType.Item: //I tried this but of course it won't work.
return new Item();
}
return null;
}
}

高度赞赏任何解决方案/示例!!

谢谢大家。

对于那些遇到相同问题的人,我已经通过不同答案的组合解决了我的问题。

类项和节点已使用 JSON 自定义转换器进行归因:

[JsonConverter(typeof(JSONTreeConverter))]
public abstract class Node
[JsonConverter(typeof(JSONTreeConverter))]
public class Item

这使每个类都可以在初始化之前使用自定义转换器。 然后,自定义转换器返回一个对象,该对象通过反射强制转换为正确的节点或项类型。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object targetObj = null;
JObject jo = JObject.Load(reader);
try
{
targetObj = Activator.CreateInstance(objectType); //instantiating concrete and known types
}
catch (Exception exc)
{
switch ((Node.NodeType)jo["Type"].Value<int>())
{
case Node.NodeType.Root:
targetObj = new Root();
break;
case Node.NodeType.Group:
targetObj = new Group();
break;
case Node.NodeType.Category:
targetObj = new ValescoCategory();
break;
case Node.NodeType.Type:
targetObj = new Type();
break;
case Node.NodeType.SubType:
targetObj = new SubType();
break;
case Node.NodeType.SubsubType:
targetObj = new SubSubType();
break;
case Node.NodeType.Item:
targetObj = new Item(); //now this is possible ;)
break;
}
}
foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.FirstOrDefault();
string jsonPath = (att != null ? att.PropertyName : prop.Name);
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
{
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
}
}
return targetObj;
}

反序列化如下:JsonConvert.DeserializeObject<Tree>(tree);

就是这样!JSON 的另一个被覆盖的函数都返回 false,并且未实现写入。

希望这对其他人有所帮助,因为我花了 3 天时间才到达。

最新更新