How To Serialize a class that derives from a Dictionary(如何序列化从字典派生的类)
问题描述
我正在尝试使用 Json.Net 在 Json 之间序列化/反序列化以下类:
I am attempting to serialize/deserialize the following class to and from Json using Json.Net:
public class ChildDictionary:Dictionary<Employee, double>
{
public string Name { get; set; }
}
我在这里找到了信息,这里,和 here 是相关的,但没有一个专门处理我们从字典派生的这种情况下的语法应该是什么样的.
I have found the information here, here, and here that are related but none of them deal specifically with what the syntax should look like for this case where we derive from a Dictionary.
Employee 成功地自行使用 Json.Net 进行序列化.它看起来像这样:
Employee successfully serializes with Json.Net on its own. It looks like this:
[JsonObject(MemberSerialization.OptIn)]
public class Employee
{
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public double Factor { get; set; }
[JsonProperty]
public List<ILoadBuilder> LoadBuilders = new List<ILoadBuilder>();
[JsonConstructor]
public LoadCause(string name, double factor, List<ILoadBuilder> loadBuilders)
{
this.Name = name;
this.DurationFactor = Factor;
this.LoadBuilders = loadBuilders;
}
}
我不在乎Json到底长什么样子,只要我能读写不丢失数据就行了
I don't care what the Json looks like in the end as long as I can write and read it without losing data
对完成此操作的代码有何建议?自定义 JsonConverter 或 Attributes 都是很好的解决方案.
Any suggestions of what the code to accomplish this should look like? Both a Custom JsonConverter or Attributes are fine solutions.
推荐答案
因为你的字典既有复杂的键又有额外的属性,你需要使用自定义的 JsonConverter
来序列化和反序列化这个类.下面是一个可以完成这项工作的转换器.它分两部分处理序列化:首先它使用反射来处理类上的任何读写属性,然后将对象转换为字典接口来处理键值对.后者作为具有 Key
和 Value
属性的对象数组写入 JSON,以便管理复杂的键而无需跳过额外的环节.
Because your dictionary has both a complex key and additional properties, you will need to use a custom JsonConverter
to serialize and deserialize this class. Below is a converter that should do the job. It handles the serialization in two parts: first it uses reflection to deal with any read-write properties on the class, then it casts the object to a dictionary interface to handle the key-value pairs. The latter are written to the JSON as an array of objects with Key
and Value
properties so that the complex keys are managed without needing to jump through extra hoops.
public class ComplexDictionaryConverter<K,V> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<K,V>)));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject obj = new JObject();
foreach (PropertyInfo prop in GetReadWriteProperties(value.GetType()))
{
object val = prop.GetValue(value);
obj.Add(prop.Name, val != null ? JToken.FromObject(val, serializer) : new JValue(val));
}
JArray array = new JArray();
foreach (var kvp in (IDictionary<K, V>)value)
{
JObject item = new JObject();
item.Add("Key", JToken.FromObject(kvp.Key, serializer));
item.Add("Value", kvp.Value != null ? JToken.FromObject(kvp.Value, serializer) : new JValue(kvp.Value));
array.Add(item);
}
obj.Add("KVPs", array);
obj.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
IDictionary<K, V> dict = (IDictionary<K, V>)Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in GetReadWriteProperties(objectType))
{
JToken token = obj[prop.Name];
object val = token != null ? token.ToObject(prop.PropertyType, serializer) : null;
prop.SetValue(dict, val);
}
JArray array = (JArray)obj["KVPs"];
foreach (JObject kvp in array.Children<JObject>())
{
K key = kvp["Key"].ToObject<K>(serializer);
V val = kvp["Value"].ToObject<V>(serializer);
dict.Add(key, val);
}
return dict;
}
private IEnumerable<PropertyInfo> GetReadWriteProperties(Type type)
{
return type.GetProperties().Where(p => p.CanRead && p.CanWrite && !p.GetIndexParameters().Any());
}
}
要使用转换器,您可以像这样使用 [JsonConverter]
属性标记您的类(确保泛型参数与您的类继承自的字典的参数匹配):
To use the converter, you can mark your class with a [JsonConverter]
attribute like this (be sure the generic parameters match those of the dictionary your class inherits from):
[JsonConverter(typeof(ComplexDictionaryConverter<Employee, double>))]
public class ChildDictionary : Dictionary<Employee, double>
{
...
}
这是一个完整的往返演示:
Here is a demo showing a full round-trip:
class Program
{
static void Main(string[] args)
{
ChildDictionary dict = new ChildDictionary();
dict.Name = "Roster";
dict.Add(new Employee { Id = 22, Name = "Joe", HireDate = new DateTime(2012, 4, 17) }, 1923.07);
dict.Add(new Employee { Id = 45, Name = "Fred", HireDate = new DateTime(2010, 8, 22) }, 1415.25);
string json = JsonConvert.SerializeObject(dict, Formatting.Indented);
Console.WriteLine(json);
dict = JsonConvert.DeserializeObject<ChildDictionary>(json);
Console.WriteLine("Name: " + dict.Name);
foreach (var kvp in dict)
{
Console.WriteLine("Employee Id: " + kvp.Key.Id);
Console.WriteLine("Employee Name: " + kvp.Key.Name);
Console.WriteLine("Employee Hire Date: " + kvp.Key.HireDate);
Console.WriteLine("Amount: " + kvp.Value);
Console.WriteLine();
}
}
}
[JsonConverter(typeof(ComplexDictionaryConverter<Employee, double>))]
public class ChildDictionary : Dictionary<Employee, double>
{
public string Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime HireDate { get; set; }
}
输出:
{
"Name": "Roster",
"KVPs": [
{
"Key": {
"Id": 22,
"Name": "Joe",
"HireDate": "2012-04-17T00:00:00"
},
"Value": 1923.07
},
{
"Key": {
"Id": 45,
"Name": "Fred",
"HireDate": "2010-08-22T00:00:00"
},
"Value": 1415.25
}
]
}
Name: Roster
Employee Id: 22
Employee Name: Joe
Employee Hire Date: 4/17/2012 12:00:00 AM
Amount: 1923.07
Employee Id: 45
Employee Name: Fred
Employee Hire Date: 8/22/2010 12:00:00 AM
Amount: 1415.25
小提琴:https://dotnetfiddle.net/fTfoIk
这篇关于如何序列化从字典派生的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何序列化从字典派生的类
基础教程推荐
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01