You need to enable JavaScript to run this app. Unity如何在OnValidate中仅校验Inspector面板被修改的变量值
优惠活动
大模型
产品
解决方案
定价
更多

Unity如何在OnValidate中仅校验Inspector面板被修改的变量值

解决方案

方案1:校验逻辑下沉到Stat类(推荐)

利用Unity的ISerializationCallbackReceiver接口,让每个Stat实例自己负责自身的校验逻辑,修改哪个实例就只会触发哪个实例的校验,完全不需要在父类遍历所有变量,性能最优也符合单一职责原则。
修改后的代码如下:

using UnityEngine;

[System.Serializable]
public class Stat : ISerializationCallbackReceiver
{
    [SerializeField] private float _value;
    public float Value 
    { 
        get => _value;
        set => _value = value; 
    }

    // 序列化完成后自动调用,Inspector修改值后会触发该方法
    public void OnAfterDeserialize()
    {
        if (_value < 0)
        {
            // 也可以选择自动修正值,比如 _value = 0; 替代抛异常
            throw new System.ArgumentException($"Stat值不能小于0,当前值为{_value}");
        }
    }

    public void OnBeforeSerialize()
    {
        // 序列化前逻辑,不需要可留空
    }
}

public class TestClass : MonoBehaviour
{
    public Stat stat1;
    public Stat stat2;
    public Stat stat3;

    void Start(){}
    // 完全不需要写OnValidate逻辑
}

方案2:父类缓存旧值对比校验

如果一定要把校验逻辑放在TestClass中,可以缓存所有变量的旧值,每次OnValidate触发时只对比校验发生变化的变量:

using UnityEngine;

public class TestClass : MonoBehaviour
{
    public Stat stat1;
    public Stat stat2;
    public Stat stat3;

    private float _oldStat1Val;
    private float _oldStat2Val;
    private float _oldStat3Val;

    void Start()
    {
        // 初始化缓存值
        _oldStat1Val = stat1.Value;
        _oldStat2Val = stat2.Value;
        _oldStat3Val = stat3.Value;
    }

    private void OnValidate()
    {
        // 仅校验值发生变化的变量
        if (stat1.Value != _oldStat1Val)
        {
            if (stat1.Value < 0)
                throw new System.ArgumentException($"Error with stat1,值为{stat1.Value}");
            _oldStat1Val = stat1.Value;
        }
        else if (stat2.Value != _oldStat2Val)
        {
            if (stat2.Value < 0)
                throw new System.ArgumentException($"Error with stat2,值为{stat2.Value}");
            _oldStat2Val = stat2.Value;
        }
        else if (stat3.Value != _oldStat3Val)
        {
            if (stat3.Value < 0)
                throw new System.ArgumentException($"Error with stat3,值为{stat3.Value}");
            _oldStat3Val = stat3.Value;
        }
    }
}

注意:方案2仅适合变量数量少的场景,后续新增变量需要同步新增缓存和校验逻辑,维护成本高于方案1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 08:06:03