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

Unity可序列化类的Nullable Int字段无法在Inspector显示的解决办法问询

解决Unity Inspector中可空值类型(int?)不显示的问题

Unity的内置序列化系统对.NET的可空值类型(像int?这种)支持得不太好,这就是为啥你的Cost字段在Inspector里看不到的原因——Unity自带的序列化器不会自动处理可空类型的序列化和界面渲染。下面给你几种靠谱的解决办法,按推荐程度排好了:

方法1:使用可序列化的包装类+自定义属性绘制器(首推)

这种方法既能保留可空类型的逻辑,又能在Inspector里获得和原生字段差不多的友好编辑体验。

步骤1:写个可序列化的可空int包装类

先定义一个专门用来封装可空int的类,把可空值拆成Unity能序列化的普通字段:

using System;
using UnityEngine;

[Serializable]
public class NullableInt
{
    [SerializeField] private int _value;
    [SerializeField] private bool _hasValue;

    // 对外暴露的可空值属性,用起来和原生int?一样
    public int? Value
    {
        get => _hasValue ? _value : null;
        set
        {
            _hasValue = value.HasValue;
            _value = value ?? default;
        }
    }

    // 加个隐式转换,让代码里赋值取值更顺手
    public static implicit operator int?(NullableInt nullableInt) => nullableInt.Value;
    public static implicit operator NullableInt(int? value) => new NullableInt { Value = value };
}

步骤2:替换原有的可空字段

修改你的CellType类,把int? Cost换成NullableInt Cost就行:

[Serializable]
public class CellType {
    [SerializeField] public NullableInt Cost; 
    [SerializeField] public Color MaterialColor;
}

步骤3:自定义Inspector绘制器(可选但强烈推荐)

默认情况下,Inspector会显示_hasValue和_value两个字段,看着有点乱。我们可以写个自定义属性绘制器,把它改成带勾选框的数值输入框——勾选就表示有值,不勾选就是null:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(NullableInt))]
public class NullableIntDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // 拿到包装类里的两个序列化字段
        var hasValueProp = property.FindPropertyRelative("_hasValue");
        var valueProp = property.FindPropertyRelative("_value");

        EditorGUI.BeginProperty(position, label, property);

        // 先绘制字段的前缀标签
        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

        // 把区域拆成两部分:左边放勾选框,右边放数值输入框
        var toggleRect = new Rect(position.x, position.y, 20, position.height);
        var valueRect = new Rect(position.x + 25, position.y, position.width - 25, position.height);

        // 绘制勾选框,控制是否有值
        hasValueProp.boolValue = EditorGUI.Toggle(toggleRect, hasValueProp.boolValue);

        // 没勾选的时候灰掉输入框,避免误操作
        EditorGUI.BeginDisabledGroup(!hasValueProp.boolValue);
        valueProp.intValue = EditorGUI.IntField(valueRect, valueProp.intValue);
        EditorGUI.EndDisabledGroup();

        EditorGUI.EndProperty();
    }
}

做完这步,你的Inspector里Cost字段就会变成一个带勾选框的输入框,体验和原生字段完全一致。

方法2:用特殊标记值替代可空类型(简单但不优雅)

如果不想写额外的类和绘制器,可以用一个特殊的int值来代表“无值”,比如int.MinValue:

[Serializable]
public class CellType {
    [SerializeField] public int Cost = int.MinValue; // 用MinValue表示null
    [SerializeField] public Color MaterialColor;

    // 对外提供可空的访问属性,方便代码里判断
    public int? CostValue => Cost == int.MinValue ? null : Cost;
}

这种方法的缺点是你得在代码里时刻记得判断这个特殊值,一不小心就容易出bug,适合简单场景临时用用。

方法3:利用SerializeReference(Unity 2019.3+)

Unity 2019.3及以上版本支持[SerializeReference]特性,能序列化引用类型,我们可以用这个来实现可空值:

[Serializable]
public class NullableIntWrapper : ISerializationCallbackReceiver
{
    public int? Value;

    [SerializeField] private int _serializedValue;
    [SerializeField] private bool _hasValue;

    // 序列化前把可空值拆成普通字段
    public void OnBeforeSerialize()
    {
        _hasValue = Value.HasValue;
        _serializedValue = Value ?? default;
    }

    // 反序列化后把普通字段还原成可空值
    public void OnAfterDeserialize()
    {
        Value = _hasValue ? _serializedValue : null;
    }
}

然后在CellType里用这个类:

[Serializable]
public class CellType {
    [SerializeReference] public NullableIntWrapper Cost; 
    [SerializeField] public Color MaterialColor;
}

不过这种方法需要手动处理序列化回调,而且SerializeReference本来是给多态类型用的,用来处理简单的可空值有点大材小用了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:51:42