Dictionary serialization woes

I’m trying to serialise a large Dictionary via the network by turning it into a byte array, but I’m falling at the first hurdle or being able to serialise a dictionary to a byte array and back. You could repro my problem making an empty project and attaching the script below to any GameObject.

The deserialise in RtsPlayer.Awake fails with this error:
SerializationException: The constructor to deserialize an object of type Rts.Dict was not found.

I’ve tried the solutions given in every article/question on the subject I could find, some of which are linked in the code, but I hit the same problem every time. Can anyone offer any help?

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Assertions;
using Rts;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;


namespace Rts
{
	class BinarySerialisation
	{
		// Serialisation functions: http://answers.unity3d.com/questions/800344/deserialization-issue-with-dictionary.html
		public static byte[] ObjectToByteArray<T>(T obj)
		{
			MemoryStream m = new MemoryStream();
			if (obj != null)
			{
				BinaryFormatter b = new BinaryFormatter();
				b.Serialize(m, obj);
			}
			return m.ToArray();
		}
		public static T ByteArrayToObject<T>(byte[] arrBytes)
		{
			if (arrBytes == null || arrBytes.Length < 1)
				return default(T);
			
			BinaryFormatter binForm = new BinaryFormatter();
			T obj = (T)binForm.Deserialize(new MemoryStream(arrBytes));
			return obj;
		}
	}


	// SerializableDictionary: http://answers.unity3d.com/questions/460727/how-to-serialize-dictionary-with-unity-serializati.html
	[Serializable]
	public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
	{
		[SerializeField]
		private List<TKey> keys = new List<TKey>();

		[SerializeField]
		private List<TValue> values = new List<TValue>();

		//public SerializableDictionary() {}
		//public SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) {}

		// save the dictionary to lists
		public void OnBeforeSerialize()
		{
			keys.Clear();
			values.Clear();
			foreach(KeyValuePair<TKey, TValue> pair in this)
			{
				keys.Add(pair.Key);
				values.Add(pair.Value);
			}
		}

		// load dictionary from lists
		public void OnAfterDeserialize()
		{
			this.Clear();

			if(keys.Count != values.Count)
				throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable."));

			for(int i = 0; i < keys.Count; i++)
				this.Add(keys_, values*);*_

* }*
* }*

* [Serializable]*
* class Dict : SerializableDictionary<int, string>{}*

* public class RtsPlayer : MonoBehaviour*
* {*
* void Awake()*
* {*
* Dict simpleDictionary = new Dict();*
* simpleDictionary[7] = “foo”;*
* string foo = simpleDictionary[7];*
* byte[] simpleDictionaryBytes = BinarySerialisation.ObjectToByteArray(simpleDictionary);*
* Dict pendingActionsOut = BinarySerialisation.ByteArrayToObject(simpleDictionaryBytes); // Fails with the following callstack:*

_ /_
_
SerializationException: The constructor to deserialize an object of type Rts.Dict was not found._
_
System.Runtime.Serialization.ObjectRecord.LoadData (System.Runtime.Serialization.ObjectManager manager, ISurrogateSelector selector, StreamingContext context) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization/ObjectManager.cs:577)_
_
System.Runtime.Serialization.ObjectManager.DoFixups () (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization/ObjectManager.cs:84)_
_
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (System.IO.BinaryReader reader) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:145)_
_
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header& headers) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:110)_
_
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:179)_
_
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:136)_
_
Rts.BinarySerialisation.ByteArrayToObject[Dict] (System.Byte arrBytes) (at Assets/Scripts/RtsPlayer.cs:35)_
_
Rts.RtsPlayer.Awake () (at Assets/Scripts/RtsPlayer.cs:88)*_
_ */_

* Debug.LogError(“If we got here it worked”);*
* }*
* }*
}

In case anyone else finds this same issue, I believe my problem is that ISerializationCallbackReceiver is an editor only interface, so these functions don’t work at runtime.

In the editor Munchy2007’s class will work great

As i said in the comment, this fixes the issue:

[Serializable]
class Dict : SerializableDictionary<int, string>
{
    public Dict():base() { }
    public Dict(SerializationInfo info, StreamingContext context) : base(info, context) { }
}

I just tested it in Unity.

The version you posted on hastebin doesn’t implement any constructor in the Dict class. Again constructors are not inherited.