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
相关产品推荐
相关产品推荐

