Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[SerializedReferences] and ISerializationCallbackReceiver

Discussion in 'Editor & General Support' started by net8floz, Oct 13, 2020.

  1. net8floz

    net8floz

    Joined:
    Oct 21, 2017
    Posts:
    37
    Hi I'm not sure exactly where to ask this - happy to move the post.

    I'm playing with the new [SerializedReference] attribute which is totally blowing my mind but I have a bit of an issue.

    I have a interface

    Code (CSharp):
    1. public interface ISomeReferenceType {
    2.     public string Name;
    3. }
    4.  
    5. public Scriptable : ScriptableObject {
    6.     [SerializedReference]
    7.     public List<ISomeReferenceType> serializedData = new List...
    8.  
    9. }
    Which works great. The data gets serialized and persisted just fine. However things don't seem to be 100% right with the ISerializationCallbackReceiver interface.

    In addition, my scriptable object wants to build a lookup dictionary of these types after deserialize.

    Code (CSharp):
    1. ...
    2. private Dictionary<string, IHasReference> lookup = new Dict....
    3.  
    4. public void OnAfterDeserialize(){
    5.      lookup.Clear(); // lookup often null even though it has a paramater constructor
    6.  
    7.      foreach(var item in serializedData){
    8.             lookup[name] = item; // item ALWAYS null at this point, after deserialization it is no longer
    9.      }
    10.  
    11. }
    I think there's some amount of incorrect order going on here. the references are not ready when the parent does a deserialization callback. Which I suppose is fine if that's how it has to be but the name OnAfterDeserialize sort of implies my data is completely ready. Without some other hook I'll have to resort to and explore less preferred solutions and possibly end up with a larger codebase because of it.

    Am I doing something wrong ( or possibly not considering a reason that makes what I want to do impossible ) ?

    tl;dr - child reference objects are a null value when parent OnAfterDeserialize is called making the ISerializationCallbackReceiver a liar.
     
  2. net8floz

    net8floz

    Joined:
    Oct 21, 2017
    Posts:
    37
    A more complete example of the null references

    Code (CSharp):
    1.     [System.Serializable]
    2.     public class Variable : IVariable {
    3.         [SerializeField]
    4.         private string name;
    5.         [SerializeReference]
    6.         private object value;
    7.  
    8.         public void OnBeforeSerialize() {
    9.  
    10.         }
    11.  
    12.         public void OnAfterDeserialize() {
    13.             Debug.Log("On Deserialize Variable");
    14.             Debug.Log(name); // not null
    15.             Debug.Log(value); // is null
    16.         }
    17.  
    18.     }
    19.  
    20.     [SerializeField]
    21.     public class VariableList : ISerializationCallbackReceiver {
    22.         [SerializeReference]
    23.         private List<IVariable> variables = new List<IVariable>();
    24.  
    25.         public void Add(IVariable variable) {
    26.             variables.Add(variable);
    27.         }
    28.  
    29.         public void OnAfterDeserialize() {
    30.             Debug.Log("On Deserialized VariableList");
    31.             foreach (var item in variables) { // list not null
    32.                 Debug.Log(item); // list item is null
    33.             }
    34.         }
    35.  
    36.         public void OnBeforeSerialize() {
    37.  
    38.         }
    39.     }
    40.  
    41.     public class VariableHolder : ScriptableObject, ISerializationCallbackReceiver {
    42.         [SerializeReference] private VariableList serializedVariables = new VariableList();
    43.         public void OnBeforeSerialize() {
    44.         }
    45.  
    46.         public void OnAfterDeserialize() {
    47.             Debug.Log("On Deserialized SO");
    48.             Debug.Log(serializedVariables); // is null
    49.         }
    50.     }
     
  3. net8floz

    net8floz

    Joined:
    Oct 21, 2017
    Posts:
    37
  4. Stacklucker

    Stacklucker

    Joined:
    Jan 23, 2015
    Posts:
    82
    I still have the same issue in 2020.3.25, my fields marked with [SerializedReference] are null inside the OnAfterDeserialize call which makes it impossible to access and cache them in dictionaries efficiently. Any news on this?
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,844
    What news are you expecting? The bug supposedly has been fixed, so if you're encountering this can reproduce it, you should put another bug report in.
     
  6. Stacklucker

    Stacklucker

    Joined:
    Jan 23, 2015
    Posts:
    82
    I am making thread posts before filing bugs report because, as with many other people, the issue often lies with the user itself and/or questions can be resolved much quicker. Turns out I made a wrong assumption, for which I am glad because I know it saved someone at Unity from going over an unnecessary bug report.

    I should have been more clear with my first comment, but [SerializedReference] was not the root of the issue, rather the (de)serialization order of two serializable objects was, similar to this issue described here https://forum.unity.com/threads/proper-use-of-onafterdeserialize.499076/.
    I hope this helps someone else in the future from making the same mistake.