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

Unity自定义C#编辑器动态Enum字段问题求助

解决Unity编辑器中动态枚举下拉字段的空值与覆盖问题

你遇到的问题本质是初始值缺失和枚举类型不匹配时的强制覆盖导致的,咱们一步步来修复:

问题根源分析

  1. 初始状态下item.Value为null,直接传给EnumPopup会触发空引用异常;
  2. 你用?? SectionA.A1的方式虽然解决了空值,但每次切换回Section A时,不管之前有没有选过A2/A3,都会被强制设为A1,这就是覆盖问题;
  3. 另外,代码没有处理枚举类型不匹配的情况(比如之前选了Section B的B1,切换到A时直接强转SectionA会报错)。

修复方案

我们需要做三件事:保证初始值有效、切换Section时重置对应枚举的默认值、非切换场景下保留用户已选的有效值。

1. 优化Item类(确保序列化持久化)

首先把Value改成带序列化的私有字段加属性,避免重启Unity或进入Play模式后值丢失:

public class Item : MonoBehaviour 
{ 
    [HideInInspector] public Section Section; 
    [HideInInspector] [SerializeField] private System.Enum _value;

    public System.Enum Value
    {
        get => _value;
        set => _value = value;
    }
}

2. 重写Editor逻辑(处理联动与值校验)

修改ItemEditor,加入类型检查、切换时的默认值重置,以及脏对象标记:

[CustomEditor(typeof(Item))] 
public class ItemEditor : Editor 
{ 
    public override void OnInspectorGUI() 
    { 
        base.OnInspectorGUI(); 
        Item item = target as Item; 

        // 绘制Section下拉,先判断是否切换了Section
        var selectedSection = (Section)EditorGUILayout.EnumPopup("Section", item.Section);
        if (selectedSection != item.Section)
        {
            // 切换Section时,重置Value为对应枚举的默认值
            item.Section = selectedSection;
            switch (item.Section)
            {
                case Section.A:
                    item.Value = SectionA.A1;
                    break;
                case Section.B:
                    item.Value = SectionB.B1;
                    break;
            }
            // 标记对象为脏,确保修改被保存
            EditorUtility.SetDirty(item);
        }
        else
        {
            // Section未切换时,校验Value的类型是否匹配
            switch (item.Section)
            {
                case Section.A:
                    // 如果当前Value不是SectionA类型(或为空),设置默认值
                    if (!(item.Value is SectionA))
                    {
                        item.Value = SectionA.A1;
                        EditorUtility.SetDirty(item);
                    }
                    // 绘制对应枚举的下拉
                    item.Value = (SectionA)EditorGUILayout.EnumPopup("Value", (SectionA)item.Value);
                    break;
                case Section.B:
                    if (!(item.Value is SectionB))
                    {
                        item.Value = SectionB.B1;
                        EditorUtility.SetDirty(item);
                    }
                    item.Value = (SectionB)EditorGUILayout.EnumPopup("Value", (SectionB)item.Value);
                    break;
            }
        }
    } 
}

为什么这么做?

  • 切换Section时重置默认值:避免类型不匹配导致的强转异常,同时给用户一个明确的初始选项;
  • 类型校验:确保在Section未切换时,只有当Value类型不匹配时才重置,不会覆盖用户已经选择的有效值;
  • 标记脏对象:EditorUtility.SetDirty会告诉Unity这个对象的属性被修改了,需要保存到场景/预制体中,避免修改丢失;
  • 序列化优化:用[SerializeField]标记私有字段,确保Value的值能被Unity正确序列化持久化。

这样修改后,你就能实现:

  1. 第一次打开Inspector时,默认Section为A,Value为A1;
  2. 切换Section时,Value自动切换为对应枚举的第一个值;
  3. 在同一个Section下修改Value,切换回来后会保留之前的选择,不会被覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:10:46