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.

Bug [SerializeReference] is unreliable and does not give warnings when it fails.

Discussion in 'Editor & General Support' started by broots, Apr 17, 2021.

  1. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    Case # 1329878
    (Repro on 2020 LTS and 2021.2.0a13)

    According to the unity documentation on [SerializeReference] it is capable of serializing object types. This is not the case, as it fails to serialize types seemingly at random.

    Code (CSharp):
    1.  
    2. [SerializeReference, HideInInspector]
    3. private object[] serializedObjects;
    4.  
    5. // The above fails to serialize any of the following types below:
    6.  
    7. [SerializeField, HideInInspector]
    8.  
    9. private AnimationCurve[] serializedCurves;
    10.  
    11. [SerializeField, HideInInspector]
    12.  
    13. private Gradient[] serializedGradients;
    14.  
    15. [SerializeField, HideInInspector]
    16.  
    17. private string[] serializedStrings;
    18.  
    (Use case: https://github.com/CoffeeVampir3/Graphify/blob/main/Runtime/Blackboard/DataBlackboard.cs )

    From a small prod into the serializable types support, these are problematic types (they don't serialize) I found from the following sample of types:

    float
    int
    string << doesn't work
    Vector2
    Vector3
    Vector4
    Vector2Int
    Vector3Int
    Bounds
    BoundsInt
    Color
    AnimationCurve << doesnt work
    Gradient << doesnt work

    Rect
    RectInt
    bool

    (Use case: https://github.com/CoffeeVampir3/Graphify/blob/main/EditorOnly/Blackboard/FieldFactory.cs )

    There's no warning given and no indication that these types are intentionally not supported. The workaround is domain specific and requires knowledge of the possible type-set in advance.
     
    Last edited: Apr 18, 2021
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,554
    The common theme in the supported/unsupported types you are pointing out is that the unsupported types are reference types. All the other types you listed are value types.

    Aside from noticing that, I don't really understand what the purpose of SerializeReference does so I'll leave it at that.
     
    Kurt-Dekker likes this.
  3. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    8,998
    According to the example code in the documentation you need to use the
    [SerializeReference]
    attribute on the fields.
    Wouldn't that be like this?
    Code (CSharp):
    1. [SerializeReference, HideInInspector]
    2. private AnimationCurve[] serializedCurves;
    3. [SerializeReference, HideInInspector]
    4. private Gradient[] serializedGradients;
    5. [SerializeReference, HideInInspector]
    6. private string[] serializedStrings;
    Disclaimer: I'm not particularly experienced in this either, so I'm just guessing based on the documentation.
     
  4. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    The workaround code works, this is demonstrating a neccesary workaround because the serialization does not work correctly. These are the types I've found which are not serializable by [SerializeReference] and thus must be serialized manually.
     
    Last edited: Apr 17, 2021
  5. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    That's true, but the unity documentation doesn't say anything about `[SerializeReference]` only working for value types.

    From the unity docs on the subject it shows serialization working for reference types https://docs.unity3d.com/ScriptReference/SerializeReference.html

    Code (CSharp):
    1. public class BuildingBlocks : MonoBehaviour
    2. {
    3.     [SerializeReference]
    4.     public List<IShape> inventory;
    5.  
    6.     [SerializeReference]
    7.     public System.Object bin;
    8.  
    9.     [SerializeReference]
    10.     public List<System.Object> bins;
    11.  
    12.     void OnEnable()
    13.     {
    14.         if (inventory == null)
    15.         {
    16.             inventory = new List<IShape>()
    17.             {
    18.                 new Cube() {size = new Vector3(1.0f, 1.0f, 1.0f)}
    19.             };
    20.             Debug.Log("Created list");
    21.         }
    22.         else
    23.             Debug.Log("Read list");
    24.  
    25.         if (bins == null)
    26.         {
    27.             // This is supported, the 'bins' serialized field is declared as holding a collection type.
    28.             bins = new List<System.Object>() { new Cube(), new Thing() };
    29.         }
    30.  
    31.         if (bin == null)
    32.         {
    33.             // !! DO NOT USE !!
    34.             // Although, this is syntaxically correct, it is NOT supported as a valid serialization construct because the 'bin' serialized field is declared as holding a single reference type.
    35.             bin = new List<System.Object>() { new Cube() };
    36.         }
    37.     }
    There's no meaningful conclusions I can draw here, something seems fundamentally broken.
     
    Last edited: Apr 17, 2021
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,554
    Well the main difference between the examples and your code is that you're using a single shared List<object> which includes both reference and value types right?
     
  7. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    Although I'm not sure why that would be a constraint to begin with, splitting them between value types and reference types also does not work.

    You can test this for yourself:


    Code (CSharp):
    1.        
    2.         [SerializeReference]
    3.         public List<object> valueObjects = new();
    4.         [SerializeReference]
    5.         public List<object> referenceObjects = new();
    6.  
    7.         public void SplitByType<T>(T item)
    8.         {
    9.             if (item.GetType().IsValueType)
    10.             {
    11.                 valueObjects.Add(item);
    12.             }
    13.             else
    14.             {
    15.                 referenceObjects.Add(item);
    16.             }
    17.         }
    18.  
    This does not change the outcome, it still fails to serialize the same types.
     
    Last edited: Apr 17, 2021