Search Unity

4.5 - Serialization Depth

Discussion in 'Editor & General Support' started by LightStriker, May 27, 2014.

  1. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    Well this just wasted a ton of my time....

    Time to start annotating all of my private fields with [NonSerialized] :/
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Yeah... Still hoping the guys at Unity will wake up and rewrite that very bad serialization. ;)
     
  3. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    This is a fantastic share, thanks ... even more so that I discovered FullInspector which I guess was the only thing holding me back from *true* happiness ;)
     
  4. NoEscape0

    NoEscape0

    Joined:
    Sep 29, 2012
    Posts:
    16
    Basically this problem can be solved by storing all your objects that can have children of the same type in a Container that will handle children-parents relationships on serialization;
    Here is an example:

    Code (CSharp):
    1. using System;
    2. using System.Runtime.Serialization;
    3. using System.Collections.Generic;
    4.  
    5. [Serializable]
    6. public class MyObject
    7. {
    8.     [NonSerializeble]
    9.     public MyObject child;
    10. }
    11.  
    12. //this is the class that you are going to serialize
    13. [Serializable]
    14. public class ObjectsContrainer
    15. {
    16.     private List<MyObject> allObjects;
    17.     private List<serializationInfo> serializationInfos;
    18.  
    19.     //save info about the children in a way that we dont get any cycles
    20.     [OnSerializing]
    21.     private void OnSerializingStarted(StreamingContext context)
    22.     {
    23.         serializationInfos = new List<serializationInfo>();
    24.         foreach (var obj in allObjects)
    25.         {
    26.             serializationInfo info = new serializationInfo {
    27.                 parentIndex = allObjects.FindIndex(x => x == obj),
    28.                 childIndex =  allObjects.FindIndex(x => x == obj.child)
    29.             serializationInfos.Add(info);
    30.         }
    31.     }
    32.  
    33.     //restore info about the children
    34.     [OnDeserialized]
    35.     private void OnDeserialized(object o)
    36.     {
    37.         //restore connections
    38.         foreach (var info in serializationInfos)
    39.         {
    40.             var parent = allObjects[info.parentIndex];
    41.             parent.child = allObjects[info.childIndex];
    42.         }
    43.     }
    44.    
    45.     [Serializable]
    46.     private struct serializationInfo
    47.     {
    48.         public int childIndex;
    49.         public int parentIndex;
    50.     }
    51. }
    52.  
    53.  
     
  5. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    813
    Bumping this thread: I have a legitimate need for exactly 8 levels of serialization (I'm building a complex editor extension, but there are no composition cycles in my structure). Is there any way I can tell Unity to go deeper?

    It'd take days to change my architecture for this one additional level of serialization...

     
  6. bremyBBW

    bremyBBW

    Joined:
    Mar 23, 2016
    Posts:
    21
    An attribute to defined the limitation our-self would be great.
     
  7. Brogan89

    Brogan89

    Joined:
    Jul 10, 2014
    Posts:
    244
    Aggressor likes this.
  8. instruct9r

    instruct9r

    Joined:
    Aug 1, 2012
    Posts:
    148
    I don't get it. Four years after the first post and this problem is still here. Why would you limit the developer from doing something. Like @bremyBBW is suggesting you can just add an integer somewhere in the preferences, so we can change that to the number, that we want...
     
  9. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    I went with this solution and it worked.

    The unfortunate side-effect is I needed to create extra scriptable objects to do so (as I couldn't just have simple serializiable classes anymore, they HAD to be SerializedScriptableObject to work with odin).

    Not the end of the world and gets me out of the issue with Unity's 8 layer seralization limit. The downside is remaking all the values in the scriptable objects you had saved before so the earlier you can do this the better!
     
  10. guneyozsan

    guneyozsan

    Joined:
    Feb 1, 2012
    Posts:
    99
    I encountered this error for a node based navigation system between some rooms. Rooms have hotspots with references to other rooms which are eventually causing cycles. References are `private` but classes are `[Serializable]` since I load their data from a JSON API.

    I would like to ask is there a preference or drawback between adding `[NonSerialized]` attribute versus using room ID's instead of object references? Or are both equally good solutions?

    I also wonder what are we giving up when we add `[NonSerialized]` attribute?
     
  11. dshook

    dshook

    Joined:
    Jul 14, 2015
    Posts:
    11
    If you know you'll only have a limited number of children objects and don't want to go through refactoring to include all the id based methods here's the hack I came up with:

    Code (CSharp):
    1.  
    2. [System.Serializable]
    3. public class MyClass{
    4.  
    5.   [SerializeField] MyClass child0;
    6.   [SerializeField] MyClass child1;
    7.   [SerializeField] MyClass child2;
    8.   [SerializeField] MyClass child3;
    9.   [SerializeField] MyClass child4;
    10.   [SerializeField] MyClass child5;
    11.   [SerializeField] MyClass child6;
    12.  
    13.   public IEnumerable<MyClass> children{
    14.     get{
    15.       if(child0 != null){ yield return child0; }
    16.       if(child1 != null){ yield return child1; }
    17.       if(child2 != null){ yield return child2; }
    18.       if(child3 != null){ yield return child3; }
    19.       if(child4 != null){ yield return child4; }
    20.       if(child5 != null){ yield return child5; }
    21.       if(child6 != null){ yield return child6; }
    22.     }
    23.     set{
    24.       if(value == null){
    25.         child0 = null;
    26.         child1 = null;
    27.         child2 = null;
    28.         child3 = null;
    29.         child4 = null;
    30.         child5 = null;
    31.         child6 = null;
    32.         return;
    33.       }
    34.       var valueList = value.ToList();
    35.       if(valueList.Count > 0){ child0 = valueList[0]; } else { child0 = null; }
    36.       if(valueList.Count > 1){ child1 = valueList[1]; } else { child1 = null; }
    37.       if(valueList.Count > 2){ child2 = valueList[2]; } else { child2 = null; }
    38.       if(valueList.Count > 3){ child3 = valueList[3]; } else { child3 = null; }
    39.       if(valueList.Count > 4){ child4 = valueList[4]; } else { child4 = null; }
    40.       if(valueList.Count > 5){ child5 = valueList[5]; } else { child5 = null; }
    41.       if(valueList.Count > 6){ child6 = valueList[6]; } else { child6 = null; }
    42.  
    43.       if(valueList.Count > 7){
    44.         Debug.LogError("Max child count exceeded");
    45.         return;
    46.       }
    47.     }
    48.   }
    49. }
    50.  
    Use at your own peril :)