使用Json.NET PopulateObject

时间:2019-07-17 23:35:53

标签: c# json json.net

我想以JSON格式加载稀疏数据,以获取缺失数据填充默认值的结果,但是我的默认值包括可扩展集的预定义实例,而不仅仅是固定字段。

对于(任意)示例,

类型

class Link
{
    public string Addr;
    public short Port;
    public Link() { Addr = "0.0.0.0"; Port = 80; }
    public override string ToString() { return Addr + ":" + Port.ToString(); }
}

class Targets
{
    public Link Fixed;
    public Dictionary<string, Link> Variable;
    public Targets()
    {
        Fixed = new Link() { Addr = "192.168.0.1" };
        Variable = new Dictionary<string, Link>
        {
            ["Common"] = new Link() { Addr = "192.168.0.2" }
        };
    }

    public override string ToString()
    {
        var result = new System.Text.StringBuilder();

        result.Append("Fixed").Append('=').Append(Fixed)
              .Append(' ');

        foreach (var link in Variable)
        {
            result.Append(link.Key).Append('=').Append(link.Value)
                  .Append(' ');
        }

        return result.ToString();
    }
}

用法

var targets = new Targets();

string json = @"{
    'Fixed': { 'Port':12345 },
    'Variable': {
        'Common': { 'Port':12345 }
    }
}";

Newtonsoft.Json.JsonConvert.PopulateObject(json, targets);

Console.WriteLine(targets);

输出Fixed=192.168.0.1:12345 Common=0.0.0.0:12345而不是所需的Fixed=192.168.0.1:12345 Common=192.168.0.2:12345

这表明所需的合并逻辑适用于固定属性,但不适用于字典中的项目,尽管事实是字典将像具有固定属性的类型一样序列化/反序列化。

1 个答案:

答案 0 :(得分:1)

花点时间解决这个问题。 Json.NET has a dedicated function for merging two JObjects together。这是修改为使用此方法的示例:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;

namespace ConsoleApp3
{
    class Link
    {
        public string Addr;
        public short Port;
        public Link() { Addr = "0.0.0.0"; Port = 80; }
        public override string ToString() { return Addr + ":" + Port.ToString(); }
    }

    class Targets
    {
        public Link Fixed;

        public Dictionary<string, Link> Variable;

        public Targets()
        {
            Fixed = new Link() { Addr = "192.168.0.1" };
            Variable = new Dictionary<string, Link>
            {
                ["Common"] = new Link() { Addr = "192.168.0.2" },
                ["Common2"] = new Link() { Addr = "192.168.0.25" }
            };
        }

        public override string ToString()
        {
            var result = new System.Text.StringBuilder();

            result.Append("Fixed").Append('=').Append(Fixed)
                  .Append(' ');

            foreach (var link in Variable)
            {
                if (link.Key != "Variable")
                    result.Append(link.Key).Append('=').Append(link.Value)
                      .Append(' ');
            }

            return result.ToString();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var targets = new Targets();

            JObject o1 = JObject.Parse( @"{
                'Fixed': { 'Port':12345 },
                'Variable': {
                    'Common': { 'Port':12345 }
                }
            }");
            JObject o2 = JObject.FromObject(targets);
            o2.Merge(o1, new JsonMergeSettings
            {
                // union array values together to avoid duplicates
                MergeArrayHandling = MergeArrayHandling.Union 
            });

            string json = o2.ToString();

            Console.WriteLine(json);
            JsonConvert.PopulateObject(json, targets);

            Console.WriteLine(targets);

            Console.ReadKey();
        }
    }
}

输出为:

{
  "Fixed": {
    "Addr": "192.168.0.1",
    "Port": 12345
  },
  "Variable": {
    "Common": {
      "Addr": "192.168.0.2",
      "Port": 12345
    },
    "Common2": {
      "Addr": "192.168.0.25",
      "Port": 80
    }
  }
}
Fixed=192.168.0.1:12345 Common=192.168.0.2:12345 Common2=192.168.0.25:80

由OP编辑:扩展为扩展方法,无需额外的ToString /反序列化:

    static class SerializerExtensions
    {
        public static T MergeObject<T>(this JsonSerializer serializer, JsonReader json, T target)
        {
            JObject o1 = JObject.FromObject(target, serializer);
            JObject o2 = serializer.Deserialize(json) as JObject;
            o1.Merge(o2, new JsonMergeSettings
            {   // union array values together to avoid duplicates
                MergeArrayHandling = MergeArrayHandling.Union,
                // an explicit null removes an existing item
                MergeNullValueHandling = MergeNullValueHandling.Merge,
            });

            serializer.Populate(o1.CreateReader(), target);
            return target;
        }

        public static T MergeObject<T>(this JsonSerializer serializer, JsonReader json, JObject template)
        {
            JObject o1 = template.DeepClone() as JObject;
            JObject o2 = serializer.Deserialize(json) as JObject;
            o1.Merge(o2, new JsonMergeSettings
            {   // union array values together to avoid duplicates
                MergeArrayHandling = MergeArrayHandling.Union,
                // an explicit null removes an existing item
                MergeNullValueHandling = MergeNullValueHandling.Merge,
            });

            return serializer.Deserialize<T>(o1.CreateReader());
        }
    }