C# 使用Json.NET PopulateObject将稀疏数据合并到字典中
我希望加载JSON格式的稀疏数据,以获得用默认值填充缺失数据的结果,但我的默认值包括可扩展集的预定义实例,而不仅仅是固定字段 比如说(任意的) 类型 输出C# 使用Json.NET PopulateObject将稀疏数据合并到字典中,c#,json,json.net,C#,Json,Json.net,我希望加载JSON格式的稀疏数据,以获得用默认值填充缺失数据的结果,但我的默认值包括可扩展集的预定义实例,而不仅仅是固定字段 比如说(任意的) 类型 输出Fixed=192.168.0.1:12345公共=0.0.0:12345而不是所需的Fixed=192.168.0.1:12345公共=192.168.0.2:12345 这表明所需的合并逻辑适用于固定属性,但不适用于字典中的项,尽管字典会像具有固定属性的类型一样进行序列化/反序列化。下面是修改后使用此方法的示例: using Newtons
Fixed=192.168.0.1:12345公共=0.0.0:12345
而不是所需的Fixed=192.168.0.1:12345公共=192.168.0.2:12345
这表明所需的合并逻辑适用于固定属性,但不适用于字典中的项,尽管字典会像具有固定属性的类型一样进行序列化/反序列化。下面是修改后使用此方法的示例:
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();
}
}
}
按OP编辑:细化为扩展方法,无需额外的字符串/反序列化:
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());
}
}
静态类序列化
{
公共静态T合并对象(此JsonSerializer序列化程序、JsonReader json、T目标)
{
JObject o1=JObject.FromObject(目标,序列化程序);
JObject o2=序列化程序。反序列化(json)为JObject;
o1.合并(o2,新JsonMergeSettings
{//将数组值合并在一起以避免重复
MergeArrayHandling=MergeArrayHandling.Union,
//显式null将删除现有项
MergeNullValueHandling=MergeNullValueHandling.Merge,
});
填充(o1.CreateReader(),目标);
回报目标;
}
公共静态合并对象(此JsonSerializer序列化程序、JsonReader json、JObject模板)
{
JObject o1=template.DeepClone()作为JObject;
JObject o2=序列化程序。反序列化(json)为JObject;
o1.合并(o2,新JsonMergeSettings
{//将数组值合并在一起以避免重复
MergeArrayHandling=MergeArrayHandling.Union,
//显式null将删除现有项
MergeNullValueHandling=MergeNullValueHandling.Merge,
});
返回序列化程序。反序列化(o1.CreateReader());
}
}
非常好;意图是非常清楚的;比我最终设计的定制JsonConverter要好得多。细化:这需要1个序列化、1个ToString和2个反序列化来进行反序列化/合并,但是可以通过在o2
上用序列化程序和CreateReader替换JsonConvert来消除ToString和额外的反序列化,如果合并相同的“模板”,则可以缓存FromObject并交换合并方向重复。更正,不能完全删除FromObject
序列化,但是如果重复使用相同的“模板”,则可以深度克隆结果。我已将这些改进添加为扩展类,并删除了未使用的SerializerSettings。如果您反对,请随时恢复第二次编辑。
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
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());
}
}