You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中SerializeReference数组添加元素时断言失败问题求助

问题分析与解决方案

断言错误根源

你遇到的IsInSyncWithParentSerializedObject()断言失败,是因为在属性绘制流程中直接修改序列化属性并强制提交(ApplyModifiedProperties()),破坏了Unity序列化系统的同步状态:

  • CreatePropertyGUI执行时,父SerializedObject可能处于未完成的编辑状态,强制提交会导致子属性与父对象的序列化状态不同步,触发断言检查失败。
  • 直接赋值managedReferenceValue后未通过Undo系统记录操作,也会导致序列化流程异常。

修复与功能实现代码

1. 基类与派生类定义(补充你缺失的部分)

namespace Test
{
    public abstract class BaseClass
    {
        public string baseCommonField;
    }

    [System.Serializable]
    public class DerivedClass1 : BaseClass
    {
        public int derivedIntField;
    }

    [System.Serializable]
    public class DerivedClass2 : BaseClass
    {
        public float derivedFloatField;
    }
}

2. 修正后的编辑器PropertyDrawer代码

namespace Editor
{
    using System;
    using System.Linq;
    using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine;
    using UnityEngine.UIElements;
    using Test;

    [CustomPropertyDrawer(typeof(BaseClass), true)]
    public class SubclassPropertyDrawer : PropertyDrawer
    {
        public override VisualElement CreatePropertyGUI(SerializedProperty property)
        {
            var root = new VisualElement();

            // 1. 创建派生类选择下拉框
            var classOptions = GetDerivedClassNames();
            var classSelector = new PopupField<string>(classOptions, GetCurrentClassName(property))
            {
                label = "选择派生类"
            };
            classSelector.RegisterValueChangedCallback(evt =>
            {
                var targetType = Type.GetType($"Test.{evt.newValue}");
                if (targetType == null) return;

                // 用Undo记录操作,确保序列化同步与可撤销
                Undo.RecordObject(property.serializedObject.targetObject, "切换派生类类型");
                property.managedReferenceValue = Activator.CreateInstance(targetType);
                EditorUtility.SetDirty(property.serializedObject.targetObject);
                property.serializedObject.Update();
            });
            root.Add(classSelector);

            // 2. 初始化空引用(避免数组新增元素时的null状态)
            if (property.managedReferenceValue == null)
            {
                Undo.RecordObject(property.serializedObject.targetObject, "初始化派生类实例");
                property.managedReferenceValue = Activator.CreateInstance(typeof(DerivedClass1));
                EditorUtility.SetDirty(property.serializedObject.targetObject);
                property.serializedObject.Update();
            }

            // 3. 绘制派生类字段
            var foldout = new Foldout { text = property.displayName };
            var propertyField = new PropertyField(property, string.Empty);
            foldout.Add(propertyField);
            root.Add(foldout);

            return root;
        }

        // 获取所有可序列化的BaseClass派生类名称
        private string[] GetDerivedClassNames()
        {
            return AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(assembly => assembly.GetTypes())
                .Where(type => type.IsSubclassOf(typeof(BaseClass)) && !type.IsAbstract && type.IsSerializable)
                .Select(type => type.Name)
                .ToArray();
        }

        // 获取当前引用的类名称
        private string GetCurrentClassName(SerializedProperty property)
        {
            return property.managedReferenceValue?.GetType().Name ?? string.Empty;
        }
    }
}

关键修复点说明

  1. 序列化同步修复:
    • 移除ApplyModifiedProperties(),改用Undo.RecordObject记录修改操作,配合EditorUtility.SetDirty标记对象需要保存,最后用property.serializedObject.Update()刷新状态,完全符合Unity编辑器的序列化工作流程,避免同步异常。
  2. 派生类选择功能:
    • 通过反射自动获取所有可序列化的BaseClass派生类,生成下拉选项,实现一键切换派生类类型。
  3. 属性绘制优化:
    • 移除了不可靠的枚举器遍历子属性逻辑,直接用PropertyField绘制整个序列化属性,Unity会自动处理不同派生类的字段显示,代码更简洁可靠。

注意事项

  • 所有派生类必须标记[Serializable]特性,否则Unity无法序列化它们。
  • 基类BaseClass可以是抽象类,但需确保派生类无抽象成员且可实例化。
  • [CustomPropertyDrawer(typeof(BaseClass), true)]中的true表示该Drawer自动应用于所有派生类,无需重复编写。

内容的提问来源于stack exchange,提问作者Kousen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:46:17