Search code examples
c#dictionaryjson.netdeserializationjson-deserialization

JsonConvert.DeserializeObject() cannot deserialize the string properly


I'm trying store this Dictionary as json:

Dictionary<string, Dictionary<string, Word>> _cateList;
//class Word
public Word{
        private string _title;
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                if (string.IsNullOrEmpty(value)){
                    throw new Exception();
                }
                _title = value;
            }
        }

        //key:category, value:definition
        private Dictionary<string,string> _categorizedDefinition;
        public Dictionary<string, string> CategorizedDefinition
        {
            get
            {
                return _categorizedDefinition;
            }

        }
}

So basically there 3 dictionaries inside each other. First I serialize the dictionary with some sample code with JsonConvert.Serialize, the output json file looks like this:

//json code
{
  "biology": {
    "biology": {
      "Title": "Tree",
      "CategorizedDefinition": {
        "Biology": "A plant"
      }
    }
  }
}
//c# code
Dictionary<string, string> temp = new Dictionary<string, string>()
  { {"Biology", "A plant" } };
Word wd = new Word("Tree", temp);
_cateList.Add("biology", new Dictionary<string, Word>()
  {
       {"biology", wd }
  });

But when I use these code to deserilize the json:

_cateList = await DataJsonHandler.LoadFromJsonFile();
//method code
public async static Task<Dictionary<string, Dictionary<string, Word>>> LoadFromJsonFile()
{
    Dictionary<string, Dictionary<string, Word>> tempDic;
    StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("CategorizedWords.json");
    using (StreamReader sr = new StreamReader(awaitfile.OpenStreamForReadAsync()))
    {
    //this lines got the same string in the original json file
     string lines = sr.ReadToEnd();
     tempDic = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, Word>>>(lines);
    }
     return tempDic;
}

And serilize it again, I got:

{
  "biology": {
    "biology": {
      "Title": "Tree",
      "CategorizedDefinition": null
    }
  }
}

Not sure what happened here to make the dictionary in Word object gone, did I miss something?


Solution

  • You forgot the setter on CategorizedDefinition. You need that in order for newtonsoft to set the property value when deserializing.

    public Dictionary<string, string> CategorizedDefinition
    {
        get =>  _categorizedDefinition;
        set => _categorizedDefinition = value; // < --magic here
    }
    

    But since you are using a constructor for the Word class, you may be forgetting to set _categorizedDefinition inside that constructor. Something like this would do:

    // constructor
    public Word(string title, Dictionary<string, string> categorizedDefinition)
    {
        // ignoring title for now, because it already works.
        this._categorizedDefinition = categorizedDefinition;
    }
    
    private Dictionary<string, string> _categorizedDefinition
    public Dictionary<string, string> CategorizedDefinition
    {
        get =>  _categorizedDefinition;
        set => _categorizedDefinition = value;
    }