うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】SerializedProperty の Type や FieldInfo を取得する

SerializedProperty.propertyPath から . 区切りで手繰っていけば
FieldInfo が取得できるので Type が取得できる

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
 
public static class SerializedPropertyUtility
{
    /// <summary>
    /// SerializedProperty から FieldInfo を取得する
    /// </summary>
    public static FieldInfo GetFieldInfo(this SerializedProperty property)
    {
        FieldInfo GetField(Type type, string path)
        {
            return type.GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
        }
 
        var parentType = property.serializedObject.targetObject.GetType();
        var splits = property.propertyPath.Split('.');
        var fieldInfo = GetField(parentType, splits[0]);
        for (var i = 1; i < splits.Length; i++)
        {
            if (splits[i] == "Array")
            {
                i += 2;

                if (i >= splits.Length)
                    continue;
 
                var type = fieldInfo.FieldType.IsArray
                    ? fieldInfo.FieldType.GetElementType()
                    : fieldInfo.FieldType.GetGenericArguments()[0];
                 
                fieldInfo = GetField(type, splits[i]);
            }
            else
            {
                fieldInfo = i + 1 < splits.Length && splits[i + 1] == "Array"
                    ? GetField(parentType, splits[i])
                    : GetField(fieldInfo.FieldType, splits[i]);
            }
 
            if (fieldInfo == null)
                throw new Exception("Invalid FieldInfo. " + property.propertyPath);
 
            parentType = fieldInfo.FieldType;
        }
        
        return fieldInfo;
    }
     
    /// <summary>
    /// SerializedProperty から Field の Type を取得する 
    /// </summary>
    /// <param name="property">SerializedProperty</param>
    /// <param name="isArrayListType">array や List の場合要素の Type を取得するか</param>
    public static Type GetPropertyType(this SerializedProperty property, bool isArrayListType = false)
    {
        var fieldInfo = property.GetFieldInfo();
 
        // 配列の場合は配列のTypeを返す
        if (isArrayListType && property.isArray && property.propertyType != SerializedPropertyType.String)
            return fieldInfo.FieldType.IsArray
                ? fieldInfo.FieldType.GetElementType()
                : fieldInfo.FieldType.GetGenericArguments()[0];

        return fieldInfo.FieldType;
    }
}

サンプル

f:id:hacchi_man:20200302223945p:plain

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
  
public class SampleMonoBehaviour : MonoBehaviour
{
    [SerializeField]
    private List<SampleClass> _samples = new List<SampleClass>
    {
        new SampleClass()
    };
         
    [Serializable]
    private class SampleClass
    {
        [SerializeField]
        private List<Vector2> _vector2s = new List<Vector2>()
        {
            Vector2.one,
        };
    }
}
 
[CustomEditor(typeof(SampleMonoBehaviour))]
public class SampleMonoBehaviourEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var samples = serializedObject.FindProperty("_samples");
        var element = samples.GetArrayElementAtIndex(0);
        var vector2s = element.FindPropertyRelative("_vector2s");
                 
        EditorGUILayout.LabelField(samples.GetFieldInfo().Name);  // _samples
        EditorGUILayout.LabelField(vector2s.GetFieldInfo().Name);  // _vector2s
        EditorGUILayout.LabelField(intValue.GetFieldInfo().Name);  // _intValue
 
        EditorGUILayout.Space();
         
        EditorGUILayout.LabelField(samples.GetPropertyType(true).Name);  // SampleClass
        EditorGUILayout.LabelField(vector2s.GetPropertyType(true).Name); // Vector2
        EditorGUILayout.LabelField(intValue.GetPropertyType().Name); // Int32
    }
}