0

I have a class that I serialize & deserialize with json.

public class ItemTemplate
{
    public string LuaPath;
    public string Category = "Clutter";
    public List<string> Slots = new List<string>();
    public double Weight = 1.0;
    public bool IsStackable = true;

    public ItemTemplate(string cat, List<string> slots, double weight, bool isStack, string lua)
    {
        Category = cat;
        Slots = new List<string>(slots);
        Weight = weight;
        IsStackable = isStack;
        LuaPath = lua;
    }
}

public class ItemTemplates
{
    public Dictionary<string, ItemTemplate> Items = new Dictionary<string, ItemTemplate>();
}

In file it looks like this

{
    "Items": {
        "SmallStone": {
            "LuaPath": "Items/SmallRock",
            "Category": "Projectile",
            "Slots": [
                "RightHand",
                "LeftHand"
            ],
            "Weight": 0.1,
            "IsStackable": true
        }
    }
}

I use this function to serialize this

public static (T, string) ReadFromJson<T>(string path)
{
    try
    {
        JsonSerializer js = new JsonSerializer();               
        StreamReader sr = new StreamReader(path);
        JsonReader jr = new JsonTextReader(sr);             
        T obj = js.Deserialize<T>(jr);
        sr.Close();
        jr.Close();
        return (obj, "");
    }
    catch (Exception e)
    {
        return (default(T), e.Message);
    }
}

After I renamed "Slots" to "ValidContainers" in both C# files and json file I get following error:

Value cannot be null.
Parameter name: collection

I have no idea what's going on. It works only when I leave old "Slots" name in json file.

krokots
  • 45
  • 5
  • What do you mean by "in both C# files and json file I get following error"? How do you get an error in a _JSON_ file? – Sweeper Mar 06 '21 at 14:15
  • I found out what's going on, I should have included also a constructor in this code samples. I was passing an empty list to new List() – krokots Mar 06 '21 at 14:21
  • So a fix to this problem is to add an parameterless constructor for ItemTemplate. I think json deserializer has to use constructor with parameters if there is no other, and passes empty list there, which produces the bug at a point of creating a new list. – krokots Mar 06 '21 at 14:27
  • It seems weird to me the way you deserialize this json.... why not use the static method JsonConvert.DeserializeObject?? – Jonathan Alfaro Mar 06 '21 at 14:39
  • @JonathanAlfaro - Likely OP is deserializing using a `StreamReader` because Newtonsoft recommends that to improve memory performance, see https://www.newtonsoft.com/json/help/html/Performance.htm#MemoryUsage. – dbc Mar 06 '21 at 14:40
  • Your `ItemTemplate` class has a single parameterized constructor. When that happens Json.NET will use it, and match JSON properties to constructor parameters **by case-invariant name**. See [JSON.net: how to deserialize without using the default constructor?](https://stackoverflow.com/q/23017716/3744182) and [Json.net `JsonConstructor` constructor parameter names](https://stackoverflow.com/a/43034838/3744182). So try modifying your constructor parameter names to be the same as the corresponding properties, it should work. – dbc Mar 06 '21 at 14:43
  • As an aside, rather than manually closing the readers, it is recommended to dispose of them automatically via a `using` statement. – dbc Mar 06 '21 at 14:46
  • @dbc but that only really improves memory performance when using actual streams like an http connection... and it only makes a difference when you are processing hughe files... for the json he is showing here it might actually be counter productive – Jonathan Alfaro Mar 06 '21 at 14:47
  • @JonathanAlfaro - I don't see why it would ever be counter productive, streaming deserialization will always be at least a little more performant than loading + deserializing afterwards. It's true that recommendation only really matters for JSON larger than 80K or so but we don't know the size of OP's actual JSON, the JSON in the question might be trimmed down to make a [mcve]. – dbc Mar 06 '21 at 14:49
  • Fixing the constructor parameter names fixes deserialization, see https://dotnetfiddle.net/S0jQWR. Close as a duplicate of the questions I linked to above? – dbc Mar 06 '21 at 14:58
  • @krokots - has your question been fully answered by these comments? – dbc Mar 06 '21 at 16:49
  • 1
    Yes exactly, just adding a parameterless constructor fixed that bug. – krokots Mar 06 '21 at 17:32

0 Answers0