unity SerializedProperty 详解
SerializedProperty 是 Unity 编辑器脚本中用于安全、通用地访问和修改序列化对象属性的核心类。它与 SerializedObject 和 Editor 类配合使用,能够自动处理撤销(Undo)、预制件(Prefab)覆盖以及多对象编辑等复杂场景。
为什么需要 SerializedProperty?
在 Unity 编辑器中直接通过反射修改组件字段存在诸多隐患:无法正确处理 [SerializeField] private 字段、预制件实例的修改无法持久化、Undo 系统不生效、多对象编辑时容易出错等。SerializedProperty 提供了一套统一的、由 Unity 序列化系统支持的解决方案,就像戴上了一双“安全操作手套”,让你在编辑数据时:
- ✅ 自动支持撤销(Ctrl+Z)
- ✅ 正确标记预制件属性覆盖
- ✅ 批量修改多个对象
- ✅ 无需关心字段的访问修饰符
基本使用流程
- 通过目标对象创建
SerializedObject - 使用
FindProperty获取属性的SerializedProperty - 读取或修改属性值
- 调用
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。两者的协作流程:
- Update():刷新序列化数据,确保与目标对象同步。
- FindProperty():获取属性。
- 修改值:通过
SerializedProperty的各类 Value 变量赋值。 - ApplyModifiedProperties():将修改写回目标对象,并自动注册 Undo、标记预制件覆盖。
注意事项
- 所有通过
SerializedProperty的修改必须在ApplyModifiedProperties之后才会真正应用到目标对象上。 - 在
OnInspectorGUI中,通常先调用serializedObject.Update(),最后调用serializedObject.ApplyModifiedProperties()。 - 使用
EditorGUILayout.PropertyField绘制属性时,Unity 会自动处理嵌套绘制、数组展开等。 - 对于多对象编辑,
hasMultipleDifferentValues可用来判断是否显示混合值指示。
SerializedProperty 是 Unity 编辑器扩展中不可或缺的基础设施,掌握它可以让你编写出健壮、专业且与原生 Inspector 行为一致的自定义工具。
浙公网安备 33010602011771号