通过id反序列化带有Child对象的JSON

时间:2017-06-21 14:05:14

标签: c# json xamarin json.net deserialization

我有以下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循环,你有一个例子吗?

2 个答案:

答案 0 :(得分:1)

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

因此,在您的自定义转换器中,您可以使用以下内容:

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个循环但不同之处在于,唯一的搜索就是从字典中获取列表,而且我认为这是非常小的。我希望这有助于或至少为您提供另一种方式来看待它。

答案 1 :(得分:0)

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

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类中检索节点,也不需要从每个边缘保持与图形的父关系。