使用空条件运算符?.仍触发UnassignedReferenceException求助
首先,咱们来拆解你遇到的两个核心疑问:为什么用了?.还会抛出UnassignedReferenceException,以及异常提示的是_Preset而非Preset。
为什么?.没起作用?
你写的myTarget.Preset?.ApplyTo(myTarget)逻辑上是想:如果Preset不为null,就调用ApplyTo。但这里有个Unity特有的“坑”:
你的Preset属性的getter直接返回私有字段_Preset,而_Preset是标记了[SerializeField]的引用类型字段。在Unity中,如果这类字段在Inspector里没有赋值,运行时访问它(哪怕只是读取它的值),Unity会抛出UnassignedReferenceException——这是Unity的提醒机制,防止开发者遗漏引用赋值。
而?.的执行顺序是先计算左边的表达式(也就是myTarget.Preset),再判断是否为null。所以在获取Preset属性的时候,已经触发了对_Preset字段的访问,这时候Unity就抛出了异常,根本没走到判断null的步骤。
为什么异常提示的是_Preset?
因为实际抛出异常的地方是访问私有字段_Preset的时候,公共属性Preset只是一个“中间层”,它的getter只是返回_Preset,所以异常栈会直接指向真正出问题的_Preset字段,而不是属性名。
解决办法
我们需要在属性的getter里做一层安全检查,避免直接返回未赋值的_Preset字段。利用Unity重载的==运算符(它能安全判断字段是否未赋值或为null,不会触发异常),修改你的属性:
[CreateAssetMenu()] public class Foo : ScriptableObject { [SerializeField] private Preset _Preset = null; public Preset Preset { get { // 先安全判断,避免直接访问未赋值的_Preset触发异常 return _Preset == null ? null : _Preset; } protected set { _Preset = value; } } }
这样修改后,当_Preset未赋值时,Preset属性会返回null,此时myTarget.Preset?.ApplyTo(myTarget)就会正确跳过调用,不会再抛出异常。
另外,如果你希望完全避免这类问题,也可以在Inspector里给_Preset设置一个默认值,或者在Foo的Awake方法里初始化它(如果逻辑允许的话)。
内容的提问来源于stack exchange,提问作者jeromej

