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

Feedback Generic type serialization + SerializedObject

Discussion in '2020.1 Beta' started by liortal, Apr 9, 2020.

  1. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I'm playing with 2020.1 beta, the "generics serializaton" is a nice touch (finally!).
    Is it planned to be supported together with the SerializedObject and SerializedProperty APIs ?

    Right now, in my simple example, i'm trying to iterate over a component that has a generic type as a serialized field. The SerializedProperty returns 'CachedValue`1' as the type and null as the objectReferenceValue.

    Should this work? or am i doing something wrong?

    This is my component BTW:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. /// <summary>
    6. /// Represents a value that is cached in PlayerPrefs.
    7. /// </summary>
    8. /// <typeparam name="T"></typeparam>
    9. [Serializable]
    10. public class CachedValue<T>
    11. {
    12.     [SerializeField]
    13.     private T myValue;
    14.    
    15.     // TODO: more code here - flush to PlayerPrefs when dirty.
    16. }
    17.  
    18. public class LiorScript : MonoBehaviour
    19. {
    20.     public CachedValue<int> intCache;
    21.     public CachedValue<string> stringCache;
    22.     public CachedValue<Vector3> vector3Cache;
    23. }
     

    Attached Files:

  2. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    64
    SerializedProperty.objectReferenceValue
    is to refer to an object that inherits from
    UnityEngine.Object
    , so that should be null.

    Man it's a bummer that it's not returning the generic type arguments in the name. If not, you can use a script to get the
    System.Object
    value by walking down the property path from the
    SerializedObject.target
    . Once you get that, it should be as simple as
    obj.GetType()
    .

    It's pretty useful to have a "GetObjectValue" extension method for Serialized Properties. Here's a snippet of the one I use:


    Code (CSharp):
    1. private static readonly Regex ArrayPathRegex = new Regex(
    2.     @"(?<arrayName>\w+)\[(?<index>\d+)\]",
    3.     RegexOptions.Compiled);
    4.  
    5. public static object GetValue(this SerializedProperty property,
    6.     Func<IEnumerable<string>, IEnumerable<string>> modifier = null)
    7. {
    8.     IEnumerable<string> path = property.propertyPath.Replace(".Array.data[", "[").Split('.');
    9.     if (modifier != null)
    10.     {
    11.         path = modifier(path);
    12.     }
    13.     var target = (object)property.serializedObject.targetObject;
    14.     return GetValueRecur(target, path);
    15. }
    16.  
    17. private static object GetValueRecur(object target, IEnumerable<string> path)
    18. {
    19.     if (target == null) throw new ArgumentNullException(nameof(target));
    20.  
    21.     var head = path.FirstOrDefault();
    22.     if (head == null)
    23.     {
    24.          return target;
    25.     }
    26.  
    27.     var arrayMatch = ArrayPathRegex.Match(head);
    28.     if (arrayMatch != null)
    29.     {
    30.         head = arrayMatch.Groups["arrayName"].Value;
    31.         var index = int.Parse(arrayMatch.Groups["index"].Value);
    32.         var field = target.GetType().GetField(head, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    33.         var array = field.GetValue(target) as IEnumerable;
    34.         target = array.ElementAtOrDefault(index);
    35.     }
    36.     else
    37.     {
    38.         target = target.GetType().GetField(head).GetValue(target);
    39.     }
    40.     return GetValueRecur(target, path.Skip(1));
    41. }
    42.  
    The
    Skip
    and
    ElementAt
    are
    IEnumerable
    extensions. You can browse them here: https://gitlab.com/jasonboukheir/unity-editor-extensions. You can make a simpler version that doesn't account for arrays.