SerializableDictionary


SerializableDictionary

Hello everyone !

SerializableDictionary allows you to expose dictionaries in the inspector.
I created the first version last year but I never created a thread to promote it there. As I am publishing a new version on the Asset Store soon, this is the occasion!

This new version will bring a many improvements and bug corrections.

  • Support for dictionaries of lists or arrays
  • Better layout for types that can be expanded (like quaternions, lists, or classes)

This is free and also available on GitHub

The new version 1.1.0 is not yet published on the asset store but you can already download it from there
All of your feedback is welcome, especially if you are upgrading from the previous version 1.0.3.

3495569--278494--SerializableDictionary_screenshot1.png 3495569--278495--SerializableDictionary_screenshot5.png

Hi, I am using dictionary of lists with a vector 3 as a key. Attached image is what I am shown with in inspector:
Could you help me out here?

3506919--279832--Screen Shot 2018-05-23 at 2.06.49 PM.png3506919--279832--Screen Shot 2018-05-23 at 2.06.49 PM.png

Hi and thank you!

I love the simple serializable output your dictionary gives after serialization. Well done! Also well written code, and adding new Dictionary definitions and PropertyDrawers is a breeze!

However, i came here to report an issue.

First though, let me request a feature:

Please wrap your package classes in a namespace, like this:

namespace mathieuleber
{
    public abstract class SerializableDictionaryBase<TKey, .....
    {
     ......
}

Same for the SerializableDictionaryPropertyDrawer class. Then creating new Definitions and PropertyDrawers will change slightly…

[Serializable]
public class StringBoolDictionary : mathieuleber.SerializableDictionary<string, bool> {}

and

[CustomPropertyDrawer(typeof(StringBoolDictionary))]
public class AnySerializableDictionaryPropertyDrawer : mathieuleber.SerializableDictionaryPropertyDrawer {}

Please do this for the assetstore package, as projects might contain multiple SerializableDictionary classes (like mine does), and some of them inside locked packages, so you need to have a unique handle on your package. Adding to your implementation every time we update from asset store is just extra work for us users.

Now a backstory to the errors i came to report:

When first looking for SerializableDictionary, i followed this implementation, but wondered why its so complex and the serializable output it gives is so extremely bloated.

As the author ( @vexe ) mentions, the “logical” implementation (one which you’re also using) was causing some unexplained errors, and other users had the same experience. More in this thread.

I then later found you Dictionary implementation in assetstore, and decided to give it a try. You can read more on how that went at the end of the last thread link i gave you.

Now let me describe what i did, after which the error started to appear:

  1. added some custom definitions for basic types (StringBoolDictionary, StringIntDictionary, …)
  2. added custom PropertyDrawers for them ([CustomPropertyDrawer(typeof(StringBoolDictionary))], …)
  3. Meanwhile, tinkered for a month with personal project, adding more simple type SerializableDictionaries and respective PropertyDrawers.

As you can see, no changes to your implementation at all. Weird observation - first time i added just few definitions, everything worked well (both in the scripting world, and in the custom inspector world). At some point, i guess after adding another definition for a basic type/basic type dictionary, i could not open their inspector property drawers, and after selecting the object in hierarchy, instead of the classic [+] sign add element, i got no custom editor output (not even default inspector eg DrawDefaultInspector() if you know what i mean) just empty component view with fold/unfold arrow pointing down/right.

I tried replicating the issue using new unit-test project, using just your package and adding definitions and property drawers. I was not successful to replicate the issue (sidenote: this seems to suggest, that the new update of your package has nothing to do with fixing the error).

Next, ill paste here the 2 errors i got in console, they kept repeating, i guess that’s just GUI repaint stuff:

NullReferenceException: Object reference not set to an instance of an object
  at mathieuleber.SerializableDictionaryPropertyDrawer+<EnumerateEntries>c__Iterator0.MoveNext () [0x00028] in #PROJECT_FOLDER#\Assets\Scripts\mathieuleber\SerializableDictionary\Editor\SerializableDictionaryPropertyDrawer.cs:538
  at mathieuleber.SerializableDictionaryPropertyDrawer.GetPropertyHeight (UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) [0x00080] in #PROJECT_FOLDER#\Assets\Scripts\mathieuleber\SerializableDictionary\Editor\SerializableDictionaryPropertyDrawer.cs:309
  at UnityEditor.PropertyDrawer.GetPropertyHeightSafe (UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) [0x0000f] in C:\buildslave\unity\build\Editor\Mono\ScriptAttributeGUI\PropertyDrawer.cs:36
  at UnityEditor.PropertyHandler.GetHeight (UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) [0x0008b] in C:\buildslave\unity\build\Editor\Mono\ScriptAttributeGUI\PropertyHandler.cs:216
  at UnityEditor.EditorGUI.GetPropertyHeightInternal (UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) [0x0000a] in C:\buildslave\unity\build\Editor\Mono\EditorGUI.cs:5643
  at UnityEditor.EditorGUI.GetPropertyHeight (UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) [0x00004] in C:\buildslave\unity\build\artifacts\generated\common\editor\EditorGUIBindings.gen.cs:936
  at UnityEditor.Editor.GetOptimizedGUIBlockImplementation (Boolean isDirty, Boolean isVisible, UnityEditor.OptimizedGUIBlock& block, System.Single& height) [0x000f6] in C:\buildslave\unity\build\artifacts\generated\common\editor\EditorBindings.gen.cs:259
  at UnityEditor.GenericInspector.GetOptimizedGUIBlock (Boolean isDirty, Boolean isVisible, UnityEditor.OptimizedGUIBlock& block, System.Single& height) [0x00007] in C:\buildslave\unity\build\Editor\Mono\Inspector\GenericInspector.cs:13
  at UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) [0x00331] in C:\buildslave\unity\build\Editor\Mono\Inspector\InspectorWindow.cs:1207
  at UnityEditor.InspectorWindow.DrawEditors (UnityEditor.Editor[] editors) [0x0015d] in C:\buildslave\unity\build\Editor\Mono\Inspector\InspectorWindow.cs:1022
  at UnityEditor.InspectorWindow.OnGUI () [0x00074] in C:\buildslave\unity\build\Editor\Mono\Inspector\InspectorWindow.cs:361
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000d0] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000eb] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115
  at UnityEditor.HostView.Invoke (System.String methodName, System.Object obj) [0x00013] in C:\buildslave\unity\build\Editor\Mono\HostView.cs:295
  at UnityEditor.HostView.Invoke (System.String methodName) [0x00009] in C:\buildslave\unity\build\Editor\Mono\HostView.cs:288
  at UnityEditor.HostView.InvokeOnGUI (Rect onGUIPosition) [0x000e0] in C:\buildslave\unity\build\Editor\Mono\HostView.cs:255
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
UnityEngine.Experimental.UIElements.IMGUIContainer:smile:oOnGUI(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:189)
UnityEngine.Experimental.UIElements.IMGUIContainer:HandleIMGUIEvent(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:330)
UnityEngine.Experimental.UIElements.IMGUIContainer:smile:oRepaint(IStylePainter) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:68)
UnityEngine.Experimental.UIElements.Panel:PaintSubTree(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:532)
UnityEngine.Experimental.UIElements.Panel:PaintSubTreeChildren(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:547)
UnityEngine.Experimental.UIElements.Panel:PaintSubTree(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:536)
UnityEngine.Experimental.UIElements.Panel:Repaint(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:564)
UnityEngine.Experimental.UIElements.UIElementsUtility:smile:oDispatch(BaseVisualElementPanel) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\UIElementsUtility.cs:236)
UnityEngine.Experimental.UIElements.UIElementsUtility:ProcessEvent(Int32, IntPtr) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\UIElementsUtility.cs:78)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr) (at C:\buildslave\unity\build\Runtime\IMGUI\Managed\GUIUtility.cs:175)
(Filename: Assets/Scripts/mathieuleber/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs Line: 538)

GUI Error: You are pushing more GUIClips than you are popping. Make sure they are balanced)
UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:LogError(Object)
UnityEngine.Experimental.UIElements.IMGUIContainer:smile:oOnGUI(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:277)
UnityEngine.Experimental.UIElements.IMGUIContainer:HandleIMGUIEvent(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:330)
UnityEngine.Experimental.UIElements.IMGUIContainer:smile:oRepaint(IStylePainter) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\IMGUIContainer.cs:68)
UnityEngine.Experimental.UIElements.Panel:PaintSubTree(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:532)
UnityEngine.Experimental.UIElements.Panel:PaintSubTreeChildren(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:547)
UnityEngine.Experimental.UIElements.Panel:PaintSubTree(Event, VisualElement, Matrix4x4, Rect) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:536)
UnityEngine.Experimental.UIElements.Panel:Repaint(Event) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\Panel.cs:564)
UnityEngine.Experimental.UIElements.UIElementsUtility:smile:oDispatch(BaseVisualElementPanel) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\UIElementsUtility.cs:236)
UnityEngine.Experimental.UIElements.UIElementsUtility:ProcessEvent(Int32, IntPtr) (at C:\buildslave\unity\build\Runtime\UIElements\Managed\UIElementsUtility.cs:78)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr) (at C:\buildslave\unity\build\Runtime\IMGUI\Managed\GUIUtility.cs:175)
(Filename: C:/buildslave/unity/build/Runtime/UIElements/Managed/IMGUIContainer.cs Line: 277)

And finally, how this error “disappeared”:

I’ve redownloaded your assetstore package, and updated my project files. Also i noticed there was a new update in May to your package (i was using package from April/2018), however i don’t think it was the update that finally “fixed” the error. After the update, i re-added the PropertyDrawer and Custom SerializableDictionary definitions i required in my project, oh and the namespace of course…) - so literally the code was in the same place as it was when it was giving errors (minus the update).

I hope this helps somehow. I can see the errors being internal Unity stuff, so i dont think you can do anything to fix that, but, yeah, the link i posted earlier says the same thing, and thats why @vexe made his own SerializableDictionary implementation (which i dont like, the serialized output it gives is too long for my use-case). So the issue stays. I dont know, how and if you could in any way fix it, its so difficult to reproduce.

Best of luck!

Ask if any questions,
Cheers!

Sorry the lack of response, I did not receive reply notifications!

Hi, mehtanitish!
Can you post your SerializableDictionary class definition, for example are you using SerializableDictionary<string, List> or something like that ?
Have you updated SerializableDictionary to the last version ? Do you still have problems with this older version : https://github.com/azixMcAze/Unity-SerializableDictionary/releases/tag/v1.1.0 ?

Hi watcher!
Yes, you are right, the classes should have been wrapped in a namespace. I did not did it because there was only two small classes initially. But this is a bad practice.
This is a small compatibility breaking change but I will think about it for the next update.

Thank you for the report. You are right, I am not sure how I can troubleshoot this error. If you can reproduce the problem with an example project, please send it to me and I will have a look.

Thank you for your use of SerializableDictionary!

Hey I was wondering if it is possible to use a List as a key? I see the storage is used only for Value items.

Nevermind I just implemented it myself. =)

Hi KrankyBoyGames, I was not sure if it would work correclty. Did you had to modify the property drawer and the dictionnary classes ?

Hi,
When we use an Enum as a key to a dictionary, when we add a new entry, it repeats the last enum used. Is it possible to make it so, when we press “+”, it moves the count for the enum up. It would make it way easier to create a dictionary for enum keys, instead of [pressing “+”, changing the enum, repeat], we could just press “+” enum.length times.
o/

Newtonsoft doesn’t work for iOS so we have to use utiljson, and native dictionaries don’t work for utiljson so I’m planning on using this, with saying this, can someone confirm if this will work for iOS builds?

Is this the best implementation of a Serializable Dictionary, or are there better alternatives? Anyone knows?