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

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:
    234
    Last edited: Nov 2, 2021
  2. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    258
    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,051
    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:
    5
    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:
    507
    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:
    210
    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:
    677
  11. TheRobWatling

    TheRobWatling

    Joined:
    Feb 18, 2013
    Posts:
    40
    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:
    322
    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:
    677
    [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:
    324
    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:
    24
  17. Neiist

    Neiist

    Joined:
    Sep 18, 2012
    Posts:
    26
    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:
    5,862
    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,114
    @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 at 7:56 AM
  20. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    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.