Unity中SerializedProperty访问子对象成员时出现空引用异常
Unity自定义编辑器ScriptableObject字段访问空引用问题
问题现象
开发自定义编辑器时,通过FindPropertyRelative获取到TalkerCharacter类型的SerializedProperty对象后,尝试访问其内部name成员变量时触发NullReferenceException。尽管character对应的SerializedProperty本身不为空,但调用prop.FindPropertyRelative("name").ToString()时抛出异常。
核心原因
TalkerCharacter是继承自ScriptableObject的引用类型,Unity序列化系统对这类对象的处理逻辑和值类型完全不同:
- 直接用
new TalkerCharacter()初始化的实例没有被Unity序列化系统正确注册,编辑器的SerializedProperty无法追踪其内部字段。 SerializedProperty对于ScriptableObject类型仅存储对象引用,而非直接包含其内部字段,因此不能通过FindPropertyRelative直接访问成员。
解决方案
1. 正确初始化ScriptableObject实例
在TalkerScript中,禁止用new创建TalkerCharacter,改用Unity官方提供的ScriptableObject.CreateInstance<T>()方法:
[System.Serializable] public class TalkerScript { public string text = "123"; [Space(30)] public TalkerCharacter character; public string face = ""; public TalkerScript(TalkerCharacter chr, string txt) { this.character = chr; this.text = txt; } // 无参构造中使用正确方式创建实例 public TalkerScript() { character = ScriptableObject.CreateInstance<TalkerCharacter>(); } }
2. 编辑器中正确访问ScriptableObject内部字段
在自定义编辑器的drawElementCallback中,需先获取ScriptableObject实例,再创建对应的SerializedObject来访问内部字段:
scriptList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { SerializedProperty element = scriptList.serializedProperty.GetArrayElementAtIndex(index); if (element != null) { rect.y += 2; SerializedProperty characterProp = element.FindPropertyRelative("character"); // 先判断对象引用是否为空 if (characterProp.objectReferenceValue != null) { // 创建对应ScriptableObject的SerializedObject SerializedObject characterSO = new SerializedObject(characterProp.objectReferenceValue); SerializedProperty nameProp = characterSO.FindProperty("name"); if (nameProp != null) { Debug.Log(nameProp.stringValue); // 绘制name字段到编辑器 EditorGUI.PropertyField(new Rect(rect.x, rect.y, 200, EditorGUIUtility.singleLineHeight), nameProp); } // 必须调用此方法保存修改 characterSO.ApplyModifiedProperties(); } EditorGUI.PropertyField(new Rect(rect.x, rect.y + EditorGUIUtility.singleLineHeight, 60, 60), element.FindPropertyRelative("face"), GUIContent.none); EditorGUI.TextArea(new Rect(rect.x + 60, rect.y + EditorGUIUtility.singleLineHeight, EditorGUIUtility.currentViewWidth - 260, 60), "12321"); } };
3. 额外注意事项
- 如果
TalkerCharacter是作为独立资源使用,建议通过Project面板右键创建实例(而非代码临时创建),确保资源被正确序列化存储。 - 操作
SerializedObject后必须调用ApplyModifiedProperties(),否则修改不会被保存到目标对象。
内容的提问来源于stack exchange,提问作者ev2rat
相关产品推荐
相关产品推荐

