Page 1 of 1

Failing to load List within a Dictionary<string, object>

Posted: Sun May 01, 2022 4:31 pm
by robotSmith
Hello!

I started trying to save using generic objects, and when I'm saving a Dictionary<string, object>, and I'm adding a List as an object it fails as

Code: Select all

FormatException: Expected '{' or "null", found '['.
. So far, I'm not having issues with any other type, but only Lists (I have not tried any other collections). I'm using Version 3.4.2 on Unity 2021.3.0f1.

Basically:

Code: Select all

    List<string> thisIsAList = new List<string> { "One", "Two" };
    Dictionary<string, object> references = new Dictionary<string, object>();

    public void SomeSaveMethod()
    {
        references.Add("List", thisIsAList);
        ES3.Save("References", references);
    }

    public void SomeLoadMethod()
    {
        references = ES3.Load<Dictionary<string, object>>("References");
        thisIsAList = (List<string>)references["List"];
    }
Result: FormatException: Expected '{' or "null", found '['.

I saw the same issue here but the poster did not follow through https://moodkie.com/forum/viewtopic.php?p=9529#p9529.
Is there anything that you think I can to overcome this?

Thank you in advance!

Re: Failing to load List within a Dictionary<string, object>

Posted: Sun May 01, 2022 5:07 pm
by robotSmith
I think I found the issue on what's going on on the save file, however, I'm not sure where the change would go on the code.

So if I save the code above, I will get this on the SaveFile.es3:

Code: Select all

"References" : {
		"__type" : "System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],mscorlib",
		"value" : {"strings":[
				"One","Two"
			]

		}
	},
From saving the other types, I noticed that ES3 appends the cast like: "__type" : "string""Hello", but that's not happening on Collections (I tried with an array too), there is no casting. I tried replicating that same approach by modifying the Save file, and when loading it works correctly. So this is what worked:

Code: Select all

"References" : {
		"__type" : "System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],mscorlib",
		"value" : {
			"strings":{
				"__type" : "System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],mscorlib"[
					"One","Two"
				]
			},
		}
	}

Re: Failing to load List within a Dictionary<string, object>

Posted: Mon May 02, 2022 8:58 am
by Joel
Hi there,

Because you're using 'object' rather than a strict type for Dictionary items, there is not enough type information to determine the type of the object you're loading from your Dictionary.

Your modified file works because you've wrapped it in an object which provides this type information. In your case you would need to save a List wrapped in an object rather than the List itself to be able to load it as an object. I.e.

Code: Select all

public class ListWrapper
{
	public List<string> myList;
}
However, if your Dictionary only contains List<string>, you should use Dictionary<string, List<string>> so that it is strictly typed.

All the best,
Joel

Re: Failing to load List within a Dictionary<string, object>

Posted: Mon May 02, 2022 3:36 pm
by robotSmith
Perfect! It worked out with the object wrapper.

The Dictionary contains many other types so I cannot strictly type it, basically, I let a component save and load any information they want about themselves. Before I was defining the types, but it has been hard to scale.

I created a generic wrapper with implicit conversions to make it easy on me. Thanks for your help as always :) !!!

Code: Select all

public class GenericListWrapper<T>
{
    [ES3Serializable]
    private List<T> myList = new List<T>();

    public List<T> MyList { get => myList; set => myList = value; }

    public static implicit operator List<T>(GenericListWrapper<T> wrapper)
    {
        return wrapper.MyList;
    }

    public static implicit operator GenericListWrapper<T>(List<T> list)
    {
        GenericListWrapper<T> newWrapper = new GenericListWrapper<T>();
        newWrapper.myList = list;
        return newWrapper;
    }
}

Re: Failing to load List within a Dictionary<string, object>

Posted: Mon May 02, 2022 3:52 pm
by Joel
Glad that was helpful :)

All the best,
Joel