【问题标题】:Deserializing JSON with Child objects by id按 id 反序列化带有子对象的 JSON
【发布时间】:2017-06-21 14:05:14
【问题描述】:

我有以下 JSON:

 {
    "graph": {
        "edges": [{
            "fromNode": "1",
            "toNode": "2",
            "distance": 200
        }],
        "nodes": [{
            "id": "1",
            "lat": 10.402875,
            "lng": 53.611151
        }]
    }
}

对于反序列化,我有这个类:

public class Graph {

    public Node [] nodes { get; set; }
    public Edge [] edges { get; set; }
}

public class Node {

    public string id { get; set; }
    public double lat { get; set; }
    public double lng { get; set; }
}

public class Edge {

    public string fromNode { get; set; }
    public string toNode { get; set; }
    public int distance { get; set; }
}

当我想反序列化 JSON 时,我调用这个函数:

JsonConvert.DeserializeObject<Graph> (content);

现在我想通过这样的反序列化获取边缘类中引用的节点对象:

public class Edge {

    public Node fromNode { get; set; }
    public Node toNode { get; set; }
    public int distance { get; set; }
}

你有没有反序列化后没有 foreach 循环的例子?

【问题讨论】:

  • 可以先修改JSon解析节点吗?
  • 这不可能通过简单的反序列化来实现。使用反序列化获取图形对象后,您需要编写逻辑以通过 id 获取 fromNode 和 toNode 对象
  • 有可选的逻辑通过id获取对象的例子吗?
  • 按节点 id 搜索节点集合,您就有了 id 的节点 - 听起来很简单

标签: c# json xamarin json.net deserialization


【解决方案1】:

一种方法是编写自己的JsonConverter(如图所示Here)并在反序列化过程中跟踪您的节点ID(例如Dictionnary)。然后,您可以在每次创建新的Node 时简单地检索相应的Edges

因此,在您的自定义转换器中,您将拥有如下内容:

public override object ReadJson(JsonReader reader, Type objectType
        , object existingValue, JsonSerializer serializer)
{

    Graph graph = new Graph();
    List<Edge> graphEdges = new List<Edge>();
    List<Node> graphNodes = new List<Node>();

    Dictionnary<int, List<Edge>> fromNodesMap = new Dictionnary<int, List<Edge>>();
    Dictionnary<int, List<Edge>> toNodesMap = new Dictionnary<int, List<Edge>>();

    /* Parse the 'edges' array, I'm omitting the reading stuff here */

    var edge = new Edge();

    int fromNode = Convert.ToInt32(((JValue)obj["fromNode"]).Value);
    if (fromNodesMap.Contains(fromNode)) {
        fromNodesMap[fromNode].Add(edge);
    } else {
        var edgeList = new List<Edge>();
        edgeList.Add(edge);
        fromNodesMap.Add(fromNode, edgeList);
    }

    int toNode = Convert.ToInt32(((JValue)obj["toNode"]).Value);
    if (toNodesMap.Contains(toNode)) {
        toNodesMap[toNode].Add(edge);
    } else {
        var edgeList = new List<Edge>();
        edgeList.Add(edge);
        toNodesMap.Add(toNode, edgeList);
    }

    edge.distance = Convert.ToInt32(((JValue)obj["distance"]).Value);

    graphEdges.Add(edge);

    /* Parse the 'nodes' array, I'm omitting the reading stuff here */

    var node = new Node();
    int nodeId = Convert.ToInt32(((JValue)obj["id"]).Value);
    node.lat = Convert.ToDouble(((JValue)obj["lat"]).Value);
    node.lng = Convert.ToDouble(((JValue)obj["lng"]).Value);

    var listEdgesSameFrom = fromNodesMap[nodeId];
    foreach (var edge in listEdgesSameFrom)
        edge.fromNode = node;

    var listEdgesSameTo = toNodesMap[nodeId];
    foreach (var edge in listEdgesSameTo)
        edge.toNode = node;

    graphNodes.Add(node);

    /* Read till end */

    graph.edges = graphEdges.ToArray();
    graph.nodes = graphNodes.ToArray();

    return graph;
}

免责声明我没有测试过,但逻辑在那里。

现在我知道那里有foreach 循环,但不同之处在于唯一的搜索是从字典中获取列表,我认为这非常少。我希望这对您有所帮助,或者至少为您提供另一种看待它的方式。

【讨论】:

    【解决方案2】:

    我建议你写 extension methods 让 Edge 返回节点:

    public static class ExtensionMethods
       {
           public static Node FromNode(this Edge edge, Graph graph){
                return graph.Nodes.FirstOrDefault(n => n.id.Equals(edge.fromNode);
           }
    
           public static Node ToNode(this Edge edge, Graph graph){
                return graph.Nodes.FirstOrDefault(n => n.id.Equals(edge.toNode);
           }
       }
    

    之后,您可以调用 edge.FromNode(graph) 并取回 from 节点。优点是您不需要将检索节点的方法放在 Node 类中,也不需要从每条边保持与图的父关系。

    【讨论】:

      猜你喜欢
      • 2018-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多