unity SerializedProperty 详解

SerializedProperty 是 Unity 编辑器脚本中用于安全、通用地访问和修改序列化对象属性的核心类。它与 SerializedObject 和 Editor 类配合使用,能够自动处理撤销(Undo)、预制件(Prefab)覆盖以及多对象编辑等复杂场景。

为什么需要 SerializedProperty?

在 Unity 编辑器中直接通过反射修改组件字段存在诸多隐患:无法正确处理 [SerializeField] private 字段、预制件实例的修改无法持久化、Undo 系统不生效、多对象编辑时容易出错等。SerializedProperty 提供了一套统一的、由 Unity 序列化系统支持的解决方案,就像戴上了一双“安全操作手套”,让你在编辑数据时:

  • ✅ 自动支持撤销(Ctrl+Z)
  • ✅ 正确标记预制件属性覆盖
  • ✅ 批量修改多个对象
  • ✅ 无需关心字段的访问修饰符

基本使用流程

  1. 通过目标对象创建 SerializedObject
  2. 使用 FindProperty 获取属性的 SerializedProperty
  3. 读取或修改属性值
  4. 调用 ApplyModifiedProperties 保存修改
using UnityEngine;
using UnityEditor;

public class MyObject : ScriptableObject
{
    public int myInt = 42;
}

public class SerializedPropertyExample : MonoBehaviour
{
    void Start()
    {
        MyObject obj = ScriptableObject.CreateInstance<MyObject>();
        SerializedObject serializedObject = new SerializedObject(obj);
        SerializedProperty property = serializedObject.FindProperty("myInt");
        
        Debug.Log("原始值: " + property.intValue);
        
        property.intValue = 100;
        serializedObject.ApplyModifiedProperties();
        
        Debug.Log("修改后: " + obj.myInt); // 输出 100
    }
}

 

常用变量(属性)

 
变量类型说明
name string 属性名称(只读)
displayName string 在 Inspector 中显示的友好名称(只读)
tooltip string 属性的工具提示(只读)
type string 属性类型名称(只读)
propertyType SerializedPropertyType 属性的序列化类型(只读)
propertyPath string 属性的完整路径(只读)
depth int 属性的嵌套深度(只读)
editable bool 属性是否可编辑(只读)
hasChildren bool 是否有子属性(只读)
hasVisibleChildren bool 是否有可见的子属性(只读)
isArray bool 是否为数组(只读)
isExpanded bool 在 Inspector 中是否展开
isInstantiatedPrefab bool 是否属于预制件实例(只读)
prefabOverride bool 属性值是否与预制件不同(只读)
hasMultipleDifferentValues bool 多对象编辑时是否代表多个不同值(只读)
serializedObject SerializedObject 所属的 SerializedObject(只读)

类型化取值变量

根据属性类型,使用对应的变量获取或设置值:

 
变量适用类型
intValue 整数
longValue 长整数
floatValue 浮点数
doubleValue 双精度浮点数
boolValue 布尔值
stringValue 字符串
colorValue 颜色
vector2Value / vector3Value / vector4Value 向量
vector2IntValue / vector3IntValue 整数向量
quaternionValue 四元数
rectValue / rectIntValue 矩形
boundsValue / boundsIntValue 边界
animationCurveValue 动画曲线
objectReferenceValue 对象引用
exposedReferenceValue 暴露引用(在 SerializedObject 上下文中解析)
enumValueIndex 枚举索引
enumNames / enumDisplayNames 枚举名称数组(只读)
arraySize 数组元素数量

常用公共方法

 
方法说明
ClearArray() 清空数组所有元素
Copy() 返回当前状态的迭代器副本
CountInProperty() 返回属性中元素的数量
DeleteArrayElementAtIndex(int index) 删除数组指定索引的元素
GetArrayElementAtIndex(int index) 获取数组指定索引的元素(返回 SerializedProperty)
InsertArrayElementAtIndex(int index) 在数组指定位置插入一个默认值元素
MoveArrayElement(int srcIndex, int dstIndex) 移动数组元素
Next(bool enterChildren) 移动到下一个属性(可用于遍历)
NextVisible(bool enterChildren) 移动到下一个可见属性
Reset() 重置属性为默认值
FindPropertyRelative(string relativePath) 查找相对路径的子属性

在自定义 Inspector 中的应用

最常见的用法是在自定义 Editor 中绘制属性字段,并自动处理 Undo 和预制件。

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
    SerializedProperty lookAtPoint;

    void OnEnable()
    {
        lookAtPoint = serializedObject.FindProperty("lookAtPoint");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        
        EditorGUILayout.PropertyField(lookAtPoint);
        
        // 可在此处检测变化并做出响应
        if (serializedObject.ApplyModifiedProperties())
        {
            Debug.Log("属性已修改");
        }
    }
}

 

处理嵌套属性和数组

对于嵌套对象或数组,可以通过 FindPropertyRelative 或 GetArrayElementAtIndex 进一步访问。

SerializedProperty targetsProp = serializedObject.FindProperty("targets");
targetsProp.arraySize = 3; // 设置数组大小

for (int i = 0; i < targetsProp.arraySize; i++)
{
    SerializedProperty element = targetsProp.GetArrayElementAtIndex(i);
    EditorGUILayout.PropertyField(element, new GUIContent($"元素 {i}"));
}

 

与 SerializedObject 的协作

SerializedProperty 无法独立存在,必须依附于 SerializedObject。两者的协作流程:

  1. ‌Update()‌:刷新序列化数据,确保与目标对象同步。
  2. ‌FindProperty()‌:获取属性。
  3. ‌修改值‌:通过 SerializedProperty 的各类 Value 变量赋值。
  4. ‌ApplyModifiedProperties()‌:将修改写回目标对象,并自动注册 Undo、标记预制件覆盖。

注意事项

  • 所有通过 SerializedProperty 的修改必须在 ApplyModifiedProperties 之后才会真正应用到目标对象上。
  • 在 OnInspectorGUI 中,通常先调用 serializedObject.Update(),最后调用 serializedObject.ApplyModifiedProperties()
  • 使用 EditorGUILayout.PropertyField 绘制属性时,Unity 会自动处理嵌套绘制、数组展开等。
  • 对于多对象编辑,hasMultipleDifferentValues 可用来判断是否显示混合值指示。

SerializedProperty 是 Unity 编辑器扩展中不可或缺的基础设施,掌握它可以让你编写出健壮、专业且与原生 Inspector 行为一致的自定义工具。

posted on 2026-05-15 16:52  -冷夜-  阅读(49)  评论(0)    收藏  举报

导航