Десериализация JSON в объект, имеющий абстрактные и неабстрактные классы - PullRequest
0 голосов
/ 21 октября 2019

Я хочу десериализовать следующий JSON в мой объект C # Tree. Древовидная структура не может быть отредактирована. JSON:

{
  "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;
        }
    }

Любые решения / примеры высоко ценятся !!!

Спасибо, ребята.

1 Ответ

0 голосов
/ 23 октября 2019

Для тех, кто сталкивался с такими же проблемами, я решил свою проблему с помощью комбинации разных ответов.

Классы Item и Node были приписаны пользовательскому конвертеру 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 дня, чтобы добраться до.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...