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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    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,560
    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.