【问题标题】:Serialize & Deserialize a dictionary that contain a class key序列化和反序列化包含类键的字典
【发布时间】:2017-03-08 17:15:22
【问题描述】:

我正在尝试序列化我的字典,看起来像这样:

private Dictionary<MetaDataKey, User> _dictionary;

MetaDataKey 和 Users 类如下所示:

internal class User
{
    public string UserName { get; set; }
    public string UserPassword { get; set; }
    public List<Account> Accounts { get; set; }
}
internal class Account
{
    public string Subject { get; set; }
    public string AccName { get; set; }
    public string AccPass { get; set; }
    public List<string> Notes { get; set; }
}
internal class MetaDataKey
{
    public string Name { get; set; }
    public string Password { get; set; }
}

我正在尝试将字典保存\加载到\来自这样的 json 文件:

private void DictionaryInit()
    {
        //gets the dictionary file if exists, create an empty one if not.
        string path = Directory.GetCurrentDirectory() + "\\dic.json";
        if (!File.Exists(path))
        {
            _dictionary = new Dictionary<MetaDataKey, User>();
            return;
        }
        using (StreamReader r = new StreamReader(path))
        {
            string json = r.ReadToEnd();
            _dictionary = JsonConvert.DeserializeObject<Dictionary<MetaDataKey, User>>(json);
        }
    }

    public void DictionarySave()
    {
        //save the dictionary into dic.json file
        string path = Directory.GetCurrentDirectory() + "\\dic.json";
        string json = JsonConvert.SerializeObject(_dictionary);
        File.WriteAllText(path, json);
    }

当我将新记录加载到字典并尝试保存时,我得到:

{"WpfApplication2.MetaDataKey":{"UserName":"Enter Name","UserPassword":"Enter Password","Accounts":null}}

代替:

{"WpfApplication2.MetaDataKey":{"Name":"Enter Name","Password":"Enter Password"},"WpfApplication2.User":{"UserName":"Enter Name","UserPassword":"Enter Password","Accounts":null}}

如您所知,我正在 MetaDataKey 类中获取用户字段。 即使我手动修复它,我仍然会遇到异常:

An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code

当我尝试加载非空文件时。 总之,有2个问题: 1. 错误的 json 保存。 2. json 加载错误

【问题讨论】:

  • 我们可以看一个json文件包含的例子吗?
  • 第一次它是空的,在我添加一条记录后,我在文件中得到了这个:{"WpfApplication2.MetaDataKey":{"UserName":"Enter Name","UserPassword":"Enter Password","Accounts":null}}(和我发布的一样)
  • 看起来 Newtonsoft JSON 序列化程序使用键对象的 ToString 表示作为键。默认的 ToString 表示是完整的类名 (= namespace.classname)。

标签: c# json dictionary serialization deserialization


【解决方案1】:

来自Json.Net的文档:

序列化字典时,字典的键被转换为字符串并用作 JSON 对象属性名称。可以通过重写键类型的 ToString() 或实现 TypeConverter 来自定义为键编写的字符串。 TypeConverter 还将支持在反序列化字典时再次将自定义字符串转换回来。

你有两个选择:

  1. 就像文档建议的那样:为您的 MetaDataKey 创建一个 TypeConverter 并将其与属性 ([TypeConverter(typeof(MetaDataKeyConverter))]) 链接 - 这并非易事,因为您必须自己将 MetaDataKey 转换为 json 字符串,并且从字符串反序列化。
  2. 为字典创建一个JsonConverter 并在您的JsonConvert.SerializeObjectJsonConvert.DeserializeObject 方法中使用它。
  3. 最简单的事情就是将字典转换为List&lt;KeyValuePair&lt;MetaData,User&gt;&gt;,这很简单,就像_dictionary.ToList()
    所以对于序列化:

    string json = JsonConvert.SerializeObject(_dictionary.ToList());
    

    对于反序列化:

    _dictionary = 
                JsonConvert.DeserializeObject<List<KeyValuePair<MetaDataKey, User>>>(json)
               .ToDictionary(kv => kv.Key, kv => kv.Value);
    

在大多数情况下,我会选择选项 3

【讨论】:

    【解决方案2】:

    尝试使用 JsonProperty 属性,如下所示:

    internal class User
    {
    
     [JsonProperty("UserName ")]
     public string UserName { get; set; }
    
     [JsonProperty("UserPassword")]
     public string UserPassword { get; set; }
    
     [JsonProperty("Accounts ")]
     public List<Account> Accounts { get; set; }
    }
    

    【讨论】:

    • 我得到了同样的结果。
    • 请看guide
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 2021-06-07
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    相关资源
    最近更新 更多