C# Dictionary - set values in editor, automatically clears when hitting "play"

Hello,

I have a script which contains a dictionary, the dictionary values are lists. Anyway, I set this dictionary up through editor scripts (but no inspector to view the dictionary myself).

Dictionary<string, List<IPool>> _pool;
	public Dictionary<string, List<IPool>> Pool {
		get { return _pool; }
		set { _pool = value; }
	}

I set up the pool through an editor script, and it properly adds objects to and from the pool. However, when I hit play _pool is null on the script. I have a quick test script that verifies the object pool is not null after the life of the function which creates and populates it.

[MenuItem("Meriwether/Expedition Mode/Check Object Pool")]

	static void CheckPool(){

		Debug.Log("IS POOL NULL: " + (ObjectPool.GetObjectPool().Pool == null).ToString());

	}

However, in the object pools awake call…

if (_pool == null){
			Debug.LogError("POOL WAS NULL :(");
			_pool = new Dictionary<string, List<IPool>>();
		}

Reports that _pool is null after play is hit. I even tried logging every call to get/set and making sure absolutely nothing other than the getter/setter itself references the private variable (_pool).

public Dictionary<string, List<IPool>> Pool {
		get { Debug.LogWarning("POOL GET CALLED"); return _pool;}
		set { _pool = value; Debug.LogWarning("POOL SET CALLED"); }
	}

So, the dictionary exists in the editor forever. However, as soon as I hit play it’s nulled out. Logging verifies that nothing is calling Pool Set that shouldn’t be :frowning:

Any ideas on how I can keep this dictionary live in both editor and play?

IMHO that’s because Unity cannot serialize dictionaries as explained here:

You will not be able to keep dictionaries live in both, editor and play. Instead you must use structures that Unity can serialize. Using two lists (as mentioned in the docs above) is the closest you can get. I also remember a serializable dictionary mentioned in the forums, but the ones i found did not work for me.

Note that dictionaries are fine if you populate them after hitting play (myself using them alot).

Thanks, I think I’ll give the linked-List<>'s a shot.

I would still use dictionaries, but search for SerializableDictionary in google. its a public implementation which works fine for serialization and then serialize to an xml for example.
we use it all the time, for serialization to disk but also for serialization and deserialization of webrequests

Could be helpful:

http://answers.unity3d.com/questions/45430/dictionary-of-dictionaries-how-do-i-store-this-and-assemble-it-at-runtime

I actually got it working already. Turns out I had three problems…

  1. Couldn’t serialize the dictionary. I worked around this by making my own serializable “dictionary-esque” class for this very specific use. It’s not very generic at all, but it worked great…
[System.Serializable]
public class ObjectDictionary : System.Object {
	[SerializeField]
	List<string> _keys;
	[SerializeField]
	List<ObjectDictionaryValue> _values;
	
	public ObjectDictionary(){
		_keys = new List<string>();
		_values = new List<ObjectDictionaryValue>();
	}
	
	public ObjectDictionaryValue GetValue(string key){
		return _values[GetIndex(key)];
	}
	
	public int Count(string key){
		return _values[GetIndex(key)].Values.Count;
	}
	
	int GetIndex(string key){
		if (_keys.Contains(key) == false){
			_keys.Add(key);
			_values.Add(new ObjectDictionaryValue());
		}
		return _keys.IndexOf(key);
	}
}
  1. It also cannot serialize lists of lists (originally I had List<List> _values). This one was really bizarre, I was able to fix it using:
[System.Serializable]
public class ObjectDictionaryValue : System.Object {
	[SerializeField]
	List<ExpeditionLociChild> _values;
	
	public ObjectDictionaryValue(){
		_values = new List<ExpeditionLociChild>();
	}
	
	public List<ExpeditionLociChild> Values {
		get { return _values; }
		set { _values = value; }
	}
}

So instead of List<List> - it was List - where ODV was basically just a List wrapped up in a new bow.

  1. IPool could not be serialized… IPool is a C# interface that I was using with my ExpeditionLociChild class - I wanted to write the object pool as generic as possible, so I wrote it around the interface - instead of the class (since that’s the entire point of the interface existing). I had to change it over to the class.

Now it works great!

I do want to try and find a way to get the C# interface to serialize as well though :frowning:

Thanks for the replies, guys!

1 Like