Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

C# Compiler C# 7.3 [field: SerializeField] support

Discussion in 'Experimental Scripting Previews' started by Baste, Oct 25, 2018.

  1. Midiphony-panda

    Midiphony-panda

    Joined:
    Feb 10, 2020
    Posts:
    243
    Last edited: Nov 2, 2021
  2. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    265
    I just use an extension method for this:
    Code (CSharp):
    1. using System;
    2. using UnityEditor;
    3.  
    4. public static class SerializedObjectExtensions
    5. {
    6.     public static SerializedProperty FindAutoProperty(this SerializedObject @this, string name)
    7.     {
    8.         return @this.FindProperty(GetBackingFieldName(name));
    9.     }
    10.  
    11.     public static SerializedProperty FindAutoPropertyRelative(this SerializedProperty @this, string name)
    12.     {
    13.         return @this.FindPropertyRelative(GetBackingFieldName(name));
    14.     }
    15.  
    16.     static string GetBackingFieldName(string name)
    17.     {
    18.     #if NET_STANDARD || NET_STANDARD_2_1
    19.         return string.Create(1/*<*/ + name.Length + 16/*>k__BackingField*/, name, static (span, name) =>
    20.         {
    21.             span[0] = '<';
    22.             name.AsSpan().CopyTo(span[1..]);
    23.             ">k__BackingField".AsSpan().CopyTo(span[(name.Length + 1)..]);
    24.         });
    25.     #else
    26.         return '<' + name + ">k__BackingField";
    27.     #endif
    28.     }
    29. }
     
  3. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,065
    Starting with Unity 2021.2, you can right-click any property name in the inspector and choose «Copy Property Path». This will copy the name of the property you have to use with
    SerializedObject
    .

    For earlier Unity versions, you can also switch the inspector to debug mode and hold down the alt key, this will replace the prettified names with the actual field names, though there's no way to copy them.
     
  4. Guitoon

    Guitoon

    Joined:
    May 1, 2019
    Posts:
    6
    I bump this thread because I think the support of this feature isn't totally complete.

    Currently, the behaviour of properties with the [field: SerializedField] attribute don't show in the inspector if this one is modified from his parent or default value.

    This also means it's not possible to revert or apply this new value on the origin/parent prefab.

    Tested with 2021.3.0f1

    The root prefab :

    Capture d’écran 2022-05-23 160507.png

    The variant prefab:

    Capture d’écran 2022-05-23 160610.png
    Notice that Stats is a serialized member of the class and displayed in Bold.
    And the LevelProgressionStats (which is a Serialized Property with [field: PropertyField]) is not bold even with a difference with the parent prefab. (Same case for AvatarUI and Animator fields)​
     
    Last edited: May 23, 2022
    Neiist, oscarAbraham, apkdev and 2 others like this.
  5. Kev00

    Kev00

    Joined:
    Dec 6, 2016
    Posts:
    229
    I noticed that Space and Header are not supported via this method. Is there some other way to do this now?

    [Space(5)]
    [Header("General")]

    [field: SerializeField] private UnitAttributeDefinition HitPoints{get; set;}
     
  6. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    540
    You have to add field: to all attributes, not just the SerializedField attribute
     
  7. Kev00

    Kev00

    Joined:
    Dec 6, 2016
    Posts:
    229
    thanks!
     
  8. Wobling-Quell

    Wobling-Quell

    Joined:
    Mar 2, 2022
    Posts:
    3
    It seems FormerlySerializedAs doesn't work with this, even if you append the field: to the attribute. Anyone else seen this?
     
  9. olejuer

    olejuer

    Joined:
    Dec 1, 2014
    Posts:
    211
    It does work, however the backing field is serialized with this special notation.
    I tested with a property called TestX which I then renamed to TestY like this

    [field: SerializeField, FormerlySerializedAs("<TestX>k__BackingField")] public int TestY { get; [UsedImplicitly] private set; }


    I wouldn't say this is very practical though, since your IDE will not do this for you correctly.
     
  10. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
  11. TheRobWatling

    TheRobWatling

    Joined:
    Feb 18, 2013
    Posts:
    44
    Thank you to both @olejuer and @brunocoimbra for your help, this was a real relief as I'm currently refactoring some code, and losing the references was painful.
     
  12. ParadoxSolutions

    ParadoxSolutions

    Joined:
    Jul 27, 2015
    Posts:
    325
    I use [field: SerializeField] and {get; set;} to expose properties to the UnityEvent selection editor. However I typically leave the variable names in pascalCase instead of in CamelCase or with an underscore prefix. This bugs me almost as much as the backing field prefix in older versions since the inspector will display the label in pascalCase, unlike all other properties which have their labels automatically displayed starting with an uppercase character which is the expected behavior.
     
    URocks likes this.
  13. FBones

    FBones

    Joined:
    Aug 28, 2016
    Posts:
    73
    The [field:SerializeField] does not appear to work (and throws a warning in both VisualStudio and the Editor when I try to use it with more "full-service" properties:


    Code (CSharp):
    1. [field:SerializeField]  
    2. public bool Selected
    3.     {
    4.         get => _selected;
    5.         private set
    6.         {
    7.             if (value != _selected)
    8.             {
    9.                 _selected = value;
    10.                 statusChanged = true;
    11.             }
    12.         }
    13.     }
    I get the warning:
    warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored.

    This does not seem accurate to me, for this is still a property.
    Not a big deal since in this case I have explicit backing fields I can serialize, but thought I'd mention this in case I'm doing something wrong.
     
    Neiist likes this.
  14. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    [field:SerializeField] only work for auto-properties (the ones with just `get;` or `get; set;`)
     
    Midiphony-panda likes this.
  15. Nefisto

    Nefisto

    Joined:
    Sep 17, 2014
    Posts:
    333
    The "field:" that you write before the attribute means, apply the following attribute to the field generated by the compiler to store the value of this property, this field is called the backing field and only exists when you create an auto-property as @brunocoimbra stated
     
  16. alior

    alior

    Joined:
    Sep 6, 2014
    Posts:
    25
  17. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    31
    I don't see the point of this if it only works for auto properties, I just want to have unity AND my own code do something when the property is set, which also often sets the value of a hidden private serialized field next to it. It would be so simple to be able to show certain properties in the inspector with an attribute made for it.. but well I guess I ll spend hours writing OnValidate code.

    Edit: By "unity and my own code" I mean that I want stuff to be done when the value changes whether it is done from the inspector or at runtime.
     
  18. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,838
    This is what custom inspectors/property drawers are for (or addons like Odin Inspector/Naughty Attributes). It doesn't really make sense to 'serialize' non auto-properties as how do you determine what the actual backing field is to serialise? At least with auto-properties they can be 100% sure.
     
  19. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,323
    @spiney199 I think he's not interested in serializing the property's value in this case, but just displaying the property in the Inspector, as if it was a serialized field:
    Code (CSharp):
    1. [SerializeField, HideInInspector] int health;
    2.  
    3. [ShowInInspector]
    4. public int Health
    5. {
    6.     get => health;
    7.  
    8.     set
    9.     {
    10.         if(value == health)
    11.         {
    12.             return;
    13.         }
    14.  
    15.         health = value;
    16.         HealthChanged?.Invoke(health);
    17.     }
    18. }
    I agree that this can be useful. Also, even more so, displaying methods as buttons.

    But yeah, custom editors can already be used to achieve that. But that does mean that you need to tightly couple your code base to those custom attributes, and you will be relying on the custom editors to continue working throughout the lifetime of the project, and not conflict with any other third party custom editors. Not a huge deal, but it would definitely be more optimal to have those be built into Unity. It's one of those things that would be much easier to implement on Unity's side for the default Editor.
     
    Last edited: Nov 2, 2023
    Neiist likes this.
  20. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,838
    I'm aware. Just their complaint didn't make sense in the context of serialising properties when it was nothing to do about serialisation at all.

    Even on Unity's end it would only be possible with a major overhaul to the SerializedObject/SerializedProperty system, and Unity's drawer system in general. Which it is in dire need of. Was kinda hoping that with the move to UI Toolkit they would do that, but we're still stuck with Custom Editor's and Property Drawers being useless in a majority of situations.
     
    SisusCo likes this.
  21. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    31
    I was using Odin but only for a few things so I wanted to remove it because of the massive overhead it quickly imposes.

    NaughtyAttributes can display only some types. By "display" I mean that as is it only shows them as disabled, I had to completely modify the way it handles properties to make them editable, but there again, if you want to display an int4... well you can't, because that editor code is made to work with serialized fields and only serialized fields. Meaning that bool234, matrices, etc. would have to be individually re-written to be displayed because what you need to replicate them is internal.

    upload_2023-11-4_9-42-37.png

    So yes, you can take every single type that exists and individually write a way to display them as properties, but is it my job to spend months making the editor more usable or should Unity be more usable?

    Contemplating this, I quickly looked at what people were saying about OnValidate and the first thing I read was someone complaining about the execution order between OnValidate and Awake so that also sounds super stable. Right now I'm considering sacrificing parts of my code that were working dynamically and beautifully in the editor, because that's the only sensible option I've got.
     
  22. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,838
    What overhead? It's optimised as all hell, speaking from having poked around the source code a lot.

    Mind you IMGUI in general is non-performant at scale compared to UI Toolkit, though that's a Unity thing as opposed to an Odin thing.

    Probably worth giving it another go to make use of more of it's overall features. The built-in attributes are only 1% of it's potential.
     
  23. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    31
    What I'm defending here is that it should be possible to display properties in the inspector and that it should render it using the existing PropertyDrawer of the fields of the same type, I don't think I should have to pay to just have a Set method called when I modify a value whether I am in the inspector or at runtime.
     
  24. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,838
    And I completely agree. Unfortunately Unity made the mistake of heavily coupling drawers with serialisation, making this effectively impossible without heavy-handed hacks. Hard to say whether they could fix that without a slew of breaking changes.

    Which is why tools exist to solve these problems for us (such as Odin).
     
    Neiist likes this.
  25. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    31
    We totally agree on the first part, however if tools can do things surely Unity should be able to do something about it on their own, yes Unity wasn't born yesterday but that can't be an excuse otherwise we tacitly accept that the service cannot be improved.
     
  26. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,838
    Well Odin works by heavy-handedly forcing it's way into Unity's internals and completely replacing the Editor generation system with it's PropertyTree system (hence my previous statement of heavy-handed hacks), by way of "large amounts of very ugly code" as said to me by the devs once.

    Though I suppose if they were to introduce a new back-end, they could A: Make using it configurable (like Assetdatabase V2), and B: Eventually enforce it's rollout starting with a specific Unity version, like with UI Toolkit.

    And not saying I don't expect Unity to improve. I just don't sit around waiting for it to happen and will just do it myself in the meantime.
     
  27. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    31
    After doing this for just about everything I really started wondering if that approach is the most viable one, it increasingly seems to me that either you go big using what things are exactly made for, or go home, because one man army is a thing but then never ever attempt to update anything and live in a cave for 7 years hoping what you started doing still makes sense by then x). But yes, I see what you mean and we agree on pretty much everything.
     
    spiney199 likes this.