Ceras: Trying to serialize Dictionary throws NullReferenceException
Hey, I’m currently looking for a serializer to serialize and deserialize the data which gets generated by my Unity project. I previously had a look at neuecc’s MessagePack but it has some limitations, mainly no support for circular references and the need to use attributes on all fields/properties. From some of the issues over there in which you seemed to have similar problems I found your Ceras serializer which looks promising.
I’ve tried out some simple things with it in a new empty project and found that circular references do indeed seem to work nicely (e.g. a “Node” class which has another Node as child).
One data type I need in my real project however is a ConcurrentDictionary<long, Node>. Trying to serialize/deserilize this kept throwing exceptions at me, even while simplifying the test project more and more. I finally arrived at the version below (SSCCE) which is just a simple Dictionary<int, string> but the exception persist…
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Ceras;
[ExecuteInEditMode]
[Serializable]
public class Main : MonoBehaviour
{
#region Fields
[SerializeField]
private string name;
[SerializeField]
private int id;
[NonSerialized]
private Dictionary<int, string> simpleDict = new Dictionary<int, string>();
[SerializeField]
private byte[] serializedSimpleDict;
[SerializeField]
private bool doCreate;
[SerializeField]
private bool doSerialize;
[SerializeField]
private bool doPrint;
[SerializeField]
private bool doClear;
[SerializeField]
private bool doDeserialize;
[NonSerialized]
private CerasSerializer ceras;
#endregion
#region Properties
#endregion
#region Constructor
#endregion
#region Methods
void Update()
{
if(doCreate)
{
simpleDict.Add(id, name);
doCreate = false;
}
if(ceras == null)
{
SerializerConfig config = new SerializerConfig();
config.DefaultTargets = TargetMember.AllFields;
ceras = new CerasSerializer(config);
Debug.Log("Created new CerasSerializer");
}
if(doSerialize)
{
int size = ceras.Serialize<Dictionary<int, string>>(simpleDict, ref serializedSimpleDict);
Debug.Log("Serialized to " + size + " bytes");
doSerialize = false;
}
if(doPrint)
{
Debug.Log(simpleDict.Count);
foreach(KeyValuePair<int, string> kvp in simpleDict)
{
Debug.Log(kvp.Key + " = " + kvp.Value);
}
doPrint = false;
}
if(doClear)
{
simpleDict = new Dictionary<int, string>();
doClear = false;
}
if(doDeserialize)
{
ceras.Deserialize<Dictionary<int, string>>(ref simpleDict, serializedSimpleDict);
doDeserialize = false;
}
}
#endregion
}
This is the error I’m getting:
NullReferenceException: Object reference not set to an instance of an object Ceras.Formatters.ReferenceFormatter
1[T].Serialize (System.Byte[]& buffer, System.Int32& offset, T value) (at Assets/Plugins/Ceras/Formatters/ReferenceFormatter.cs:155) (wrapper dynamic-method) System.Object.lambda_method(System.Runtime.CompilerServices.Closure,byte[]&,int&,System.Collections.Generic.Dictionary2<int, string>) Ceras.Formatters.DynamicObjectFormatter1[T].Serialize (System.Byte[]& buffer, System.Int32& offset, T value) (at Assets/Plugins/Ceras/Formatters/DynamicObjectFormatter.cs:229) (wrapper dynamic-method) System.Object.lambda_method(System.Runtime.CompilerServices.Closure,byte[]&,int&,System.Collections.Generic.Dictionary2<int, string>) Ceras.Formatters.ReferenceFormatter`1[T].Serialize (System.Byte[]& buffer, System.Int32& offset, T value) (at Assets/Plugins/Ceras/Formatters/ReferenceFormatter.cs:155) Ceras.CerasSerializer.Serialize[T] (T obj, System.Byte[]& buffer, System.Int32 offset) (at Assets/Plugins/Ceras/CerasSerializer.cs:338) Main.Update () (at Assets/Scripts/Main.cs:66)
Steps to reproduce:
- Create the above script in a Unity project
- Attach it as a Component to a GameObject in the Scene
- Enter some values, e.g. “Alpha” and 123
- Toggle the “Do Create” bool (quick and dirty way to add a button for testing)
- Check with “Do Print” that the item got added (see in Console)
- Press “Do Serialize” and the above exception is thrown (remember to manually untoggle “Do Serialize” again!)
Using this setup:
- Unity 2018.3.3f1
- Scripting Runtime Version = “.NET 4.x Equivalent”
- Scripting Backend = " IL2CPP"
- Api Compatibility Level = “.NET 4.x”
- Latest Ceras commit (Feb 10, 2019, 5c10f30b40d90fc360a32922de99507675dce31f)
Am I missing something? Or are Dictionaries not serializable?
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 17 (11 by maintainers)
Since I mainly work with Unity my main IDE is (still) MonoDevelop. While it’s not officially supported anymore (last version being 5.9.6 which comes with Unity 2017.4), newer Unity versions can still be configured to use it as IDE. The main reason I like it more than Visual Studio is that it’s much more lightweight and has better syntax highlighting (especially with the Monokai theme I use). Of course the drawback is that it’s not 100% as powerful as Visual Studio in a few aspects.
If you planned to provide precompiled versions for download anyway then that’s good. I know some repositories where only the source code is provided and the users are expected to compile everything themselves (e.g. if you want to get a new version of MonoDevelop for Windows they don’t just provide an exe for some reason…) which can be a bit of a hassle.
Yes, that was me: https://github.com/rikimaru0345/Ceras/issues/26#issuecomment-463114684 😉 I’ve seen the upload requirements Unity expects to be fulfilled and read that it can take some 4-6 weeks for a package to be approved. So the best approach might be to wait a bit after you release a stable version here on github and unless someone finds any problems with it then you could upload it to the Asset Store? And unless you fix something important in a minor version only upload major versions? Many uploaders also link to their github where users can get the latest version sooner if they need it. Just a few thoughts 😉