[Unity] Comment sérialiser un Dictionary

This post is available in english

 

Unity ne gère pas nativement la sérialisation de la classe Dictionary.

La bonne manière d’y remédier est tout simplement fournie par la documentation d’Unity.

Mais si vous n’avez pas le bon mot-clé ou le bon pointeur lorsque vous commencez à chercher, vous allez faire face à l’un des plus gros problème d’Unity : l’incroyable quantité de solutions obsolètes, hors sujet ou juste fausses que renvoi Google…

Pour résumer rapidement la documentation, l’élément clé est l’interface ISerializationCallbackReceiver. Elle vous permet d’exécuter votre propre code de sérialisation/déserialisation et donc d’utiliser des List pour enregistrer les clés / valeurs de votre Dictionary.

Le code exemple :

 

using UnityEngine;
using System;
using System.Collections.Generic;

public class SerializationCallbackScript : MonoBehaviour, ISerializationCallbackReceiver
{
	public List<int> _keys = new List<int>();
	public List<string> _values = new List<string>();

	//Unity doesn't know how to serialize a Dictionary
	public Dictionary<int,string> _myDictionary = new Dictionary<int,string>()
	{
		{3, "I"},
		{4, "Love"},
		{5, "Unity"},
	};
	
	public void OnBeforeSerialize()
	{
		_keys.Clear();
		_values.Clear();

		foreach( var kvp in _myDictionary )
		{
			_keys.Add( kvp.Key );
			_values.Add( kvp.Value );
		}
	}

	public void OnAfterDeserialize()
	{
		_myDictionary = new Dictionary<int, string>();

		for(var i = 0; i != Math.Min( _keys.Count, _values.Count ); i++ )
			_myDictionary.Add( _keys[i], _values[i] );
	}

	void OnGUI()
	{
		foreach( var kvp in _myDictionary )
				GUILayout.Label( "Key: " + kvp.Key + " value: " + kvp.Value );
	}
}

Il faut cependant être vigilant sur le fait que List ne sérialise pas les valeurs null, il faut donc les gérer soit-même en utilisant une string spécifique (avec le potentiel danger d’avoir une clé qui a la même valeur…)

Voici la version modifiée du code que j’utilise :

public void OnBeforeSerialize()
        {
            _keys.Clear();
            _values.Clear();

            foreach (var kvp in _myDictionary)
            {
                _keys.Add(kvp.Key);
                if (kvp.Value != null)
                    _values.Add(kvp.Value);
                else
                    _values.Add(NULL_STRING);
            }
        }

        public void OnAfterDeserialize()
        {
            _myDictionary = new Dictionary<SystemLanguage, string>();

            for (var i = 0; i != Math.Min(_keys.Count, _values.Count); i++)
            {
                if (_values[i].Equals(NULL_STRING))
                {
                    _myDictionary.Add(_keys[i], null);
                }
                else
                {
                    _myDictionary.Add(_keys[i], _values[i]);
                }
            }
        }

 

En espérant que cela vous fasse gagner du temps 😉

Leave a Reply

Your email address will not be published. Required fields are marked *