如何序列,从词典派生的类 [英] How To Serialize a class that derives from a Dictionary

查看:268
本文介绍了如何序列,从词典派生的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图序列化/反序列化下面的类使用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; }

}



我已经找到了信息的这里,的这里和的此处是相关的,但他们没有与语法应该是什么样子这种情况下,我们从字典中获得具体处理。

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.

员工成功对自己的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或属性都很好的解决方案。

Any suggestions of what the code to accomplish this should look like? Both a Custom JsonConverter or Attributes are fine solutions.

推荐答案

由于你的字典有一个复杂键和其他属性,则需要使用自定义的 JsonConverter 序列化和反序列化这个类。下面是应该做的工作的转换器。它处理两部分序列化:首先,它使用反射来处理的类中的任何读写性能,那么它施放的对象词典的界面来处理键 - 值对。后者将写入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; }
}



输出:

Output:

{
  "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

这篇关于如何序列,从词典派生的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆