Search Unity

Finally, a serializable dictionary for Unity! (extracted from System.Collections.Generic)

Discussion in 'Scripting' started by vexe, Jun 24, 2015.

  1. DearUnityPleaseAddSerializableDictionaries

    DearUnityPleaseAddSerializableDictionaries

    Joined:
    Sep 12, 2014
    Posts:
    135
    Unity team, please... I've been waiting for years. Implement serializable dicts.
     
    VenetianFox, Crokett, N8W1nD and 7 others like this.
  2. ZhavShaw

    ZhavShaw

    Joined:
    Aug 12, 2013
    Posts:
    173
    I love your signature!
     
  3. supernamey923834

    supernamey923834

    Joined:
    Jul 27, 2017
    Posts:
    10
    thread bump! Nothin to add and nothing to gain it seems since Unity team does not want to implement this
     
  4. DearUnityPleaseAddSerializableDictionaries

    DearUnityPleaseAddSerializableDictionaries

    Joined:
    Sep 12, 2014
    Posts:
    135
    It's the only way. The reason why Unity is called "Unity", is for you guys to unite and copy & paste my signature into your signature. Let's unite as one and do this! #Unity
     
  5. Extrys

    Extrys

    Joined:
    Oct 25, 2017
    Posts:
    345
    Currently there is a unity serialized dictionary

    adding URP you can use UnityEngine.Rendering.SerializedDictionary<T,Y>

    and it serializes ina really fancy way, but i encountered some problems with it, not sure why it is in rendering at all
     
    assertor likes this.
  6. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Thus is all well and good. I prefer to stick to matched index Lists and Arrays as I can stipulate order and link more than a key value pair.
     
  7. Fressbrett

    Fressbrett

    Joined:
    Apr 11, 2018
    Posts:
    97
    Its 2022, and no sign of serializable Dictionaries from Unity. Maybe we should print t-shirts demanding this basic quality of life feature...
     
    N8W1nD, AbgaryanFX and iDerp69 like this.
  8. Extrys

    Extrys

    Joined:
    Oct 25, 2017
    Posts:
    345
    I just tought this was by default but then i realized i was using odin UmU


    True, lol, isnt there even a place on the roadmap for it?
     
  9. Fressbrett

    Fressbrett

    Joined:
    Apr 11, 2018
    Posts:
    97
    Odin is super nice, but even it fails for serialized dictionary within prefabs variants.
     
  10. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,929
    The prefabs issue is a Unity issue with their wonky prefab serialisation and their limited API regarding prefabs. Just shunt that sort of data onto scriptable objects.

    With respect to no dictionaries in Unity... Unity's serialisation is basic for a reason: it's fast.

    It's why the SerializeReference attribute comes with a warning that it comes with additional overhead. And as fast as Odin's serialisation is, Unity's is almost always faster.

    So I can understand why it's low priority.
     
  11. losingisfun

    losingisfun

    Joined:
    May 26, 2016
    Posts:
    36
    I dont think unity will ever add dictionary serialization seeing as version 2022 now comes with the JsonNet library already added. Thats right, you get not one, but two! json serializers with every unity project!

    I've just been using JsonNet now for so long even if they did add it to Unity i doubt i'd even bother going back to it. The only real advantage it would provide is editing dictionaries from the inspector.
     
  12. Digimaster

    Digimaster

    Joined:
    Aug 8, 2017
    Posts:
    7
    Unfortunately, the serialized dictionary approach presented here is not working with List types (e.g. as values) :(
     
  13. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,929
    Well yes, because if you're using the solution on the front of this post you're essentially doing a List<List<T>>, which is not something Unity supports the serialisation of.

    You want to use a wrapper class instead, which has the list inside of it.
     
  14. losingisfun

    losingisfun

    Joined:
    May 26, 2016
    Posts:
    36
    You can create a serializable class with a list inside of it, eg

    Code (CSharp):
    1. [System.Serializable]
    2. public class MyClass
    3. {
    4.     public List<int> myList = new List<int>();
    5. }
    6.  
    7. public class Main
    8. {
    9.     // this is serializable and will be editable from the inspector
    10.     public List<MyClass> serializableList = new List<MyClass>();
    11. }
    But if you just need to serialize 2D arrays and such, honestly just use JsonNet, it'll be much cleaner
     
  15. mike143

    mike143

    Joined:
    Aug 27, 2022
    Posts:
    2
    I am unquestionably retarded.
    1) Why did I make the save load static?
    2) It was right in front of me! The console is spotless! I'll let you know if I get it to work!

    My plan is to create a custom class called "Values" that will hold a variety of variables such as tier, skin, and so on. Because the types are simple, such as string and int, I'll make the class serializable.

    THANK YOU SO MUCH!
     
  16. JustinMRodriguez

    JustinMRodriguez

    Joined:
    Aug 29, 2022
    Posts:
    1
    It seems like a good idea to have a "don't destroy on load" option.
    My first plan was to use the playerprefs approach, but I'm not sure how deserialization works. My dictionary isn't that extensive, but it does contain the enemy type and an approximation of how many of each are needed to spawn, and it's read throughout the spawn process.
     
  17. terryhbuckley

    terryhbuckley

    Joined:
    Aug 27, 2022
    Posts:
    2
    1) Make wrappers whenever you can. I realise this may sound irritating, but do it where there isn't complete chaos.
    2) IMPERATIVELY mark items with SerializeField or System.
    This is true whether or not the ISerializationCallbackReceiver interface is being used. Just ALWAYS do that, private/public/internal/protected fields equally. Be VERY clear about your intentions; the serializer appears to abide by these requirements.
    3) If a field is marked as non serialised, you may generally do whatever you want with it (as long as it doesn't directly touch the Unity API). However, if you need to change serialised properties, do it all at once. Use arrays that are only set rather than iterating over fields that are NOT marked as non-serialized.
    As an illustration, here's how I'd serialise a dictionary:
    Code (csharp):
    1.  
    2. void ISerializationCallbackReceiver.OnBeforeSerialize()
    3. _keys equals this.
    4. _values = this; keys.ToArray()
    5. ToArray(); Values;
    6.  
     
  18. notodab743

    notodab743

    Joined:
    Sep 6, 2022
    Posts:
    3
    Answer
    I just extracted the DictionaryTK, TV> code and marked the relevant fields with [SerializeField] to accomplish that. Additionally, it was somewhat refactored and cleaned up (the fields were renamed, the implementation of non-generic interfaces was deleted, and the "hashCode," "next," "key," and "value" from the "Entry" class were factored out and converted to arrays).
    The "IsWellKnownEqualityComparer" was one part that I left a remark on because I wasn't really sure about it. I ran some tests, and nothing seemed to change. Please let me know if you genuinely believe it to be crucial.
     
  19. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    121
    What is this
     
  20. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Confusion taking hold. Matched index lists and arrays are much more useful than Dictionaries IMHO.
     
    Radivarig likes this.
  21. Digimaster

    Digimaster

    Joined:
    Aug 8, 2017
    Posts:
    7
    The dictionary works in Unity Editor Mode and Unity Play Mode, but when I build to my Android target device, the dictionary cannot find the value of a key which existed before, both on the target device and in the Unity Editor and Play Mode. So building to the target device somehow changes the a hash value of the key. This problem occurs when I run the ContainsKey() method, I traced the problem down to the following line:


    var keys = myDictSerializable.Keys;
    bool hasKey = keys.Contains(myExistingKey) // hasKey == true

    myDictSerializable.ContainsKey(myExistingKey)

    //entering the ContainsKey() method, relevant line:
    int hash = _Comparer.GetHashCode(key) & 2147483647


    The hash has changed after building to the target device, e.g. from '104928' to '122816'

    So the ContainsKey() method returns false. Anyone knows why this happens and how to fix this?
     
  22. Seforius

    Seforius

    Joined:
    Jun 25, 2022
    Posts:
    10
    Seems to work perfectly for me! Great job, vexe. People like you that engineer fantastic code and give it to others for free give me faith in humanity.
     
  23. kinglotrich

    kinglotrich

    Joined:
    Jun 2, 2023
    Posts:
    29
    can pls give me 1 expamle ı did get how to use,

    ı made a new script and copied the script that contains "[Serializable, DebuggerDisplay("Count = {Count}")]"

    after that crate a new script and copied this script
    1. [Serializable]
    2. public class MyDictionary : SerializableDictionary<string, int> { }

    3. public class Test : MonoBehaviour
    4. {
    5. public MyDictionary dictionary;
    6. }
    and a get this error

    cant add script ,this scripts needs to derive from MonoBehaviour
     
  24. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,929
    All monobehaviours need to be in their own script assets. Separate the above into two files.
     
  25. makomarkus

    makomarkus

    Joined:
    Oct 28, 2020
    Posts:
    61
    Is there a gist of the latest version?