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.

SerializeReference Attribute?

Discussion in '2019.3 Beta' started by SonicBloomEric, May 15, 2019.

  1. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    1,081
    Any quick word on what the SerializeReference Attribute mentioned in the release notes is?

    [Apologies in advance: no time at present to download and install the alpha and its documentation to check if it's already documented there...]
     
  2. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    The field attribute is for serializing reference types (c# class, not structs) by reference as opposed to by value (as is the default behaviour).

    This allows:
    - Expressing graphs without having to resort to ScritableObjects for each node in the graph.
    - Polymorphic data, ex: List<IFoo>;
    - Have null fields: Standard deserialization behaviour for fields that are null is to set them to a default value of the type.

    contrived usage example:
    Code (CSharp):
    1.  
    2.  
    3. interface INode{  }
    4.  
    5. [Serializable]
    6. class RootNode : INode
    7. {
    8.    [SerializeReference] public INode left;
    9.    [SerializeReference] public INode right;
    10. }
    11.  
    12. [Serializable]
    13. class SubNode : RootNode
    14. {
    15.    [SerializeReference] INode parent;
    16. }
    17.  
    18. [Serializable]
    19. class LeafNode : INode
    20. {
    21.    [SerializeReference] public INode parent;
    22. }
    23.  
    24.  
    25. class SomeThing : ScriptableObject
    26. {
    27.     [SerializeReference]
    28.     public List<RootNode>  m_Trees;
    29. }
    30.  
    31.  
     
    Last edited: Jul 16, 2019
  3. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,619
    This is very cool!
     
    Alverik likes this.
  4. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    1,081
    Sweet, sweet heavens. @jasonm_unity3d that is huge. Is there going to be more information on this, perhaps posted in the blog? It seems to me that an update to the Serialization in Unity blog entry would be super handy. (This assumes the manual will get its own update, of course.)
     
  5. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    A blog post is in the works, but I'm not in the loop as far as the eta.
    The API documentation is ready but has yet to be published, docs team is looking into as we speak.

    Note that [SerializedReference] does come with a slight performance hit, hard to measure as it depends on context. But it's there, so it is not advised for use for the general cases (where in general, performance considerations trump just about everything else).

    But for those rare cases where the implementation/maintenance complexity does trump performance or it's a non issue as the final objects are not that big so they won't have measurable impact even if they are slower to deserialize, then this feature fits the bill.
     
    solarisn, jashan, ftejada and 5 others like this.
  6. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,284
    It's... Beautiful

    tumblr_mzcos91INP1qd2l0fo1_250.gif
     
    UNSH, Propagant, watsonsong and 21 others like this.
  7. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    1,081
    Can you quantify "performance hit" in some way?

    We'll have to benchmark our own code, of course, in the long run. We already serialize references with Serialization Callback shenanigans. My fingers are crossed that the new built-in approach is at least as fast as our custom solution...
     
    EZaca and Alverik like this.
  8. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    the extra overhead is impacted by how many types are involved and how many objects.
    In some scenarios, you I have seen slight speed ups (large graphs, small nodes), in other scenarios i've seen slowdown: Many small ScriptableObjects with one small field that is serialized by reference.

    The nature of the data model being serialized has to much of an impact to be able to say: "you can expect x% slow down, y% speed up".

    Purely anecdotally, one small lists (~20 items) with 2-3 types involved and 4-5 fields per type, one test run that I remember was .5% slower. But again, that was a synthetic test case and doesn't mean much. Will be very interesting to hear actual reports come back from our users for real world usage...
     
    ailuropoda0, ftejada, Alverik and 4 others like this.
  9. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    Will this serialize dictionaries, mainly because that's an old request and we can finally put it to bed if this solves it?
     
  10. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Sweet Lord, at last!
    *runs in circles in tears of happiness*
     
  11. DoctorShinobi

    DoctorShinobi

    Joined:
    Oct 5, 2012
    Posts:
    219
    Holy S***. Does that mean we'll be able to serialize interfaces? I'll finally be able to use interfaces without feeling like Unity is fighting me by not letting me reference them in the inspector.
     
  12. SirIntruder

    SirIntruder

    Joined:
    Aug 16, 2013
    Posts:
    49
    Nice!
    Does this means we will also get a way to get System.Object reference from SerializedProperty?
    pretty please :D
     
  13. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Wow! I can't believe this isn't mentioned in https://forum.unity.com/threads/preview-of-2019-3-features.678820/

    Serialisation support for references *and* polymorphic data? Are you kidding? It is always such a massive pain to write complex tools for unity because you need to restructure your data to work around Unity's serializer. This will make things so much easier.
     
  14. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    After some messing about, it seems very flexible so long as you are exclusively using custom classes. Also, (kind of expected) the inspector gets really weird really quickly and is frequently causes crashes when editing values of data that has been tagged as SerialiseReference. (It really likes crashing the editor!) The data does serialize and deserialize correctly - it's just that the rendering is a little broken in the inspector.

    If you need complex data structures like this that support reference serialization then you are probably putting together something relatively complex, so you will probably be manipulating this data with a custom editor of some sort...so its not such a big deal! In my test, I was able to 'poke' the data on my monobehaviour using 'ContextMenu' methods and verify that references are maintained as expected.

    Overall, very very very cool! It is a shame that we still can't reference UnityEngine.Object's via their interfaces though..! But at this point I'll take what I can get...!
     
    Alverik likes this.
  15. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    ouch. this is exactly what I wanted it to do (being able to code against interfaces and the implementation can be either a MonoBehaviour or a ScriptableObject...)
     
    MegamaDev likes this.
  16. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    Hell is officially affected by climate change!
     
  17. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    - API link: https://docs.unity3d.com/2019.3/Documentation/ScriptReference/SerializeReference.html

    - UnityEngine.Object cannot be stored in fields with the [SerializeReference] attribute, so the interface restriction remains. I don't expect that limitation to ever be lifted as it's actually a fundamental design limitation of who the serialization system is leveraged all over the unity code base.

    - Unfortunately no, Dictionary serialization is still not supported.

    -
    Does this means we will also get a way to get System.Object reference from SerializedProperty?

    Not sure what is ment by that but, you can have
    [SerializeReference] List<System.Object> data;
    . You can then access it through serialziedObject/Property and fetch the fields from the instance's class not just the System.Object class. If that makes sense?

    -
    Does that mean we'll be able to serialize interfaces? 

    Yes, but will reject objects that are descendants of UnityEngine.Object.

    And, if you happy about this feature: Please, please, please, be diligent in reporting any and all bugs through the editor as this feature was very invasive and will need love to stabilize and be rock solid.

    cheers
    -J
     
  18. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    I have wondered for a while, whether there should be some way to apply an attribute to a collection, rather than the elements. Ever since the change was made to apply attributes to the elements of the collection, there has been no way to apply attributes to a collection itself, requiring custom inspectors to override collection drawing behaviour, which was annoying but not a showstopper.

    Now that there's an attribute that fundamentally alters serialization to this extent, it sounds like this should be looked at.

    Granted, if I must serialise a collection by internal reference I could wrap it in a class, but it would be great not to have to.
     
  19. charlesb_rm

    charlesb_rm

    Unity Technologies

    Joined:
    Jan 18, 2017
    Posts:
    485
    Alverik and Prodigga like this.
  20. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    The initial proposal for Serializing References did support that specific use case, but it was later rejected during peer review: was deemed a 'nice to have' but not common enough to be worth the added dev time & complexity.

    If enough people ask for it, who knows...
     
    Alverik and Ziplock9000 like this.
  21. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,477
    I'd find applying attributes to a collection rather than its elements useful too. Here is an actual case where I would use it.
     
  22. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    1,020
    I was expecting this...
     
  23. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    Ditto. And wider use of reorderable lists. Currently the options are a custom inspector or jumping through hoops. For a previous project I had a custom root inspector to allow several custom attributes for UX purposes, allowing per-collection attributes, but that approach wouldn’t work with attributes that change serialisation behaviour.

    Anyhow, this is off topic now, I’m just sad when the opportunity for a QoL improvement is missed. The feature implemented here removes the need for huge amounts of involved boilerplate on my end as it is.
     
    phobos2077 likes this.
  24. DoctorShinobi

    DoctorShinobi

    Joined:
    Oct 5, 2012
    Posts:
    219
    That's a real bummer. Interfaces are an important part of c# since you can't use multiple inheritances with classes. If I want to implement a dependency injection solution then this limit makes it a lot less pleasant to assign implementations to interfaces.
     
    CodeRonnie, xVergilx and phobos2077 like this.
  25. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    Right, so that specific limitation is not related to serialization layer but to the 'property drawer selector' that does not allow sufficient expressiveness.
     
  26. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    182
    Oh boy! As an Odin developer, this feature is super exciting to me, as supporting custom serialization, especially in the context of the new nested prefab system, has been getting very problematic, and we've been trying to pivot our focus onto evermore sophisticated editor and workflow features instead. As such, I have a question/request related to this new attribute.

    It is becoming increasingly complicated for plugins like Odin Inspector to keep track of whether Unity is serializing something or not, as we need to create our own logic that, based on the Unity version in question,
    tries to guess for any specific type or field, whether Unity is indeed serializing it. A dazzlingly nightmarish array of factors can make a difference, from the backing type of an enum to entirely unique behaviour for many types (UnityEngine.Vector3 is not marked [Serializable], but Unity breaks the rules and serializes it anyway; we just need to hardcode stuff like this).

    With this new addition, this will only get more complicated and difficult to maintain, especially as I can imagine that a feature like this might see a lot of change, additions and adjustments as people begin to adopt it. Can we have a thread-safe API (or at least, an API that can also be invoked from Unity's loading threads during deserialization) that will let us pass in a given type and member to determine whether Unity is serializing it?

    It could, for example, take the following shape:
    Code (CSharp):
    1. SerializationType unityWillSerializeType = UnitySerializationUtility.GetSerializationType(Type type);
    2. SerializationType unityWillSerializeMember = UnitySerializationUtility.GetSerializationType(MemberInfo member);
    3.  
    4. public enum SerializationType
    5. {
    6.     NonSerialized,
    7.     SerializedNoReference,
    8.     SerializedReference // The new serialization mode triggered by this attribute
    9. }
    10.  
    Having this would solve a *lot* of issues for us! :) A single method that "documents" Unity's serialization behaviour would be much better than trying to figure it out through trial and error and sifting through year's worth of patchnotes (which we've done so far).
     
  27. MCrafterzz

    MCrafterzz

    Joined:
    Jun 3, 2017
    Posts:
    354
    Does this make it possible to serialise Vector3? Always found it weird that such a essential object that's used everywhere can't be serialised.
     
  28. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    What gave you the idea that Vector3 wasn't serializable?
     
    SolidAlloy and JeffersonTD like this.
  29. MCrafterzz

    MCrafterzz

    Joined:
    Jun 3, 2017
    Posts:
    354
    When using the System.Serialized attribute on a class with Vector3 Visual Studio warns about the variable not being serializable
     
  30. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,477
    Perhaps because the Vector3 struct isn't decorated with System.SerializableAttribute.
     
    SolidAlloy likes this.
  31. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    I always serialize Vector3 no problem:
    public Vector3 test;

    I've never noticed any issue with Vector3 and serialization.
     
  32. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    All of those types built into Unity are serializable without being marked with the System.Serializable attribute.
     
    SolidAlloy likes this.
  33. phobos2077

    phobos2077

    Joined:
    Feb 10, 2018
    Posts:
    350
    This is very exciting. I'm still learning Unity and it's quirks in editor tools department. Had to bang my head quite a bit around the limitations of the built-in serializer. I wonder how exactly the polymorphic fields will be rendered in the default inspector. Will there be some kind of "Create/Destroy" button with ability to choose a sub-class from a drop-down list?

    I was trying to implement this at some point with a custom property drawer, but ended up using plain old MonoBehaviors (creating a bunch of empty game objects - far from ideal) or ScriptableObjects (not convenient when I want this data to be specific to a scene, prefab or an object) instead via some base class.

    Features I'm missing the most in the current serializer:

    - Serialize auto-properties.
    - Serialize generic types.
    - Serialize dictionaries.
    - Provide some attribute to attach MB's and SO's to an Interface type field if these objects implement that interface (I use a workaround solution for this, but it requires creating a wrapper class for each Interface I want to expose via inspector object field).

    I wonder if there's any plans or considerations about the above features I listed.
     
    Last edited: May 28, 2019
    jfilion and Hypertectonic like this.
  34. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    you can put a
    [field: SerializeField]
    attribute on the property. the display name is ugly though

    the other 3 I want them too
     
    richardkettlewell likes this.
  35. phobos2077

    phobos2077

    Joined:
    Feb 10, 2018
    Posts:
    350
    Yeah I know but it's not a solution. The underlying backing field is compiler-generated, it's not guaranteed to remain the same. And it's ugly, as you mentioned. I'd better write some boilerplate with a normal backing field.
     
  36. dzamani

    dzamani

    Joined:
    Feb 25, 2014
    Posts:
    122
    Could you give a bit more information and / or examples about this:
    - Referenced values cannot be shared between UnityEngine.Object instances. For example, two MonoBehaviours cannot share an object that is serialized by reference. Use ScriptableObjects instead to share data.
     
  37. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    It means that you cannot have a linked list of things serialised in two MonoBehaviours and expect them to maintain being a single linked list on deserialisation. Each serialisation context would get its own copies of the objects.
     
  38. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    correct. after a serialize/deserialize cycle, both MonoBehaviours would have distinct lists.
     
  39. MCrafterzz

    MCrafterzz

    Joined:
    Jun 3, 2017
    Posts:
    354
    Will dictionary serilization support ever be added? I feel like it's quite an important feature for a lot of people
     
    TextusGames and phobos2077 like this.
  40. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    To be honest, while it would be very nice to have, it is one of the easiest things to do using ISerializationCallbackReceiver, i.e. it is not and has not been a show stopper since that interface was added, which was a rather long time ago now.

    Sure, it'd be very convenient but that's it.
     
  41. hatena_matt

    hatena_matt

    Joined:
    Feb 27, 2019
    Posts:
    1
    Is there any way to insert data into a field with [SerializeReference] from a custom inspector?
     
  42. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    What exactly are you stuck on? Just set the value on the field.
     
  43. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
  44. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    Ziplock9000 likes this.
  45. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    Just so I'm clear, would polymorphic serialization support the following situation?

    Code (CSharp):
    1. [Serializable]
    2. public class Animal
    3. {
    4.     public string name;
    5. }
    6.  
    7. [Serializable]
    8. public class Dog : Animal
    9. {
    10.     public bool isTailWagging;
    11. }
    12.  
    13. [Serializable]
    14. public class Cat : Animal
    15. {
    16.     public bool isPurring;
    17. }
    18.  
    19. // This will be the serialized class
    20. [Serializable]
    21. public class Farm
    22. {
    23.     // This will contain Animals of all types (Dogs, Cats, etc)
    24.     public List<Animal> animals;
    25.  
    26.     public Farm()
    27.     {
    28.         animals = new List<Animals>();
    29.         animals.Add(new Dog());
    30.         animals.Add(new Cat());
    31.     }
    32. }
    I know I've had problems with cases like this in the past with Unity's serialization, so it'd be a big relief to have this fixed!
     
    Dalton-Lima likes this.
  46. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    960
    Yes.
     
    Prodigga and SonicBloomEric like this.
  47. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    Awesome! Glad to hear it. Thanks for the clarification!
     
  48. HassanKhallouf

    HassanKhallouf

    Joined:
    Mar 5, 2015
    Posts:
    52
    I'm not sure if this is the thing I've been waiting for for years now or I didn't get this straight

    I tried to mess around with this thing in an empty project, the serialized field appears in the inspector as a name only, you can't fill the values of that object. so I'm not sure if this is a bug or I'm using it wrong ?

    also, what I have been waiting for is something like this

    Player Class has IMovement interface, and you can drop any component that implements IMovement in this field, but what I understood is that won't be possible since a component is already UnityEngine.Object

    if that's the case, what is this really about? is this just for data classes ? if that's the case, my original question is still there, is it a bug that it's not appearing in the inspector?
     
    CyrilGhys and AlexWige like this.
  49. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    In the latest alpha, I am seeing
    every time I perform an action on a behaviour that has a list field with SerialiseReference attribute.
     
  50. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    Sorry for the late response, was out on paternity leave.

    example:

    Code (CSharp):
    1.  
    2. [Serializable] class Boo
    3. {
    4.     public int a;
    5. }
    6.  
    7. class Foo : MonoBehaviour
    8. {
    9.     [SerializeReference] public Boo boo;
    10. }
    11.  
    12. void SomeMethodSomewhere( GameObject go )
    13. {
    14.     var foo1 = go.AddComponent(typeof(Foo)) as Foo;
    15.     var foo2 = go.AddComponent(typeof(Foo)) as Foo;
    16.     var boo = new Boo() { a =4 };
    17.  
    18.     foo1.boo = boo;
    19.     foo2.boo = boo;
    20.  
    21.     // At this point, foo1.boo == foo2.boo (same instance)
    22. }
    23.  
    but once the go gets saved and reloaded, if you where to fetch those two components back from the game object into foo1 and foo2, you would have: foo1.boo != foo2.boo

    that is because [SerializeReference] are serialized As Part of the 'root' object , in this case the Foo instances, and so can't be shared between root objects.

    But if Foo had two fields of type Boo, then one instance of Foo could have two fields point to the same Boo instance and that would be preserved during serialization/deserialization.
     
    Last edited: Jul 16, 2019