序列化和反序列化包含类键的字典

4

我将尝试对类似这样的字典进行序列化:

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类中获取Users字段。即使我手动修复它,仍然会出现异常:

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

当我尝试加载一个非空文件时,出现了两个问题: 1. JSON保存不良。 2. JSON加载不良。

我们能看到一个JSON文件包含什么样的例子吗? - maccettura
一开始它是空的,当我添加记录后,文件中会出现这个:{"WpfApplication2.MetaDataKey":{"UserName":"输入名称","UserPassword":"输入密码","Accounts":null}}(与我发布的相同) - Etian Chamay
1
看起来Newtonsoft JSON序列化器使用键对象的ToString表示作为键。默认的ToString表示是完整的类名(=命名空间.类名)。 - ckuri
2个回答

3
Json.Net的文档中得知:

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

您有两个选项:

  1. like the documentation suggests: create a TypeConverter for your MetaDataKey and link it with attribute ([TypeConverter(typeof(MetaDataKeyConverter))]) - This is not trivial as you will have to convert the MetaDataKey to json string yourself, and also deserialize from string.
  2. Create a JsonConverter for dictionary and use it in your JsonConvert.SerializeObject and JsonConvert.DeserializeObject methods.
  3. The simplest thing you can do is to convert the dictinary to a List<KeyValuePair<MetaData,User>> this is easy as _dictionary.ToList()
    So for serializing:

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

    And for deserialize:

    _dictionary = 
                JsonConvert.DeserializeObject<List<KeyValuePair<MetaDataKey, User>>>(json)
               .ToDictionary(kv => kv.Key, kv => kv.Value);
    
对于大多数情况,我会选择第三个选项。

-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; }
}

我得到了相同的结果。 - Etian Chamay
请参阅此指南 - Einav Oss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接