Unity的判空逻辑以及优化思路

问题描述

在C#6及以上版本中,加入了一项特别好用的运算符:Null条件运算符?.和?[]可以用来方便的执行判空操作,当运算符左侧操作数不为null时才会进行访问操作,否则直接返回null。

于是我们对于判空有了两种选择

  • 使用 == 或 != 进行判断
  • 使用?. 或 ?[] 进行判断.

在C#中, 这两种选择完全等价. 但在Unity中, 这两种选择的结果并不相同. 

 

Unity中的绝大部分类型都继承自 UnityEngine.Object. 这个类型对 "==" 和 "!=" 运算符进行了重载, 以适应Unity中的判断逻辑. 但是并未对 "?." 运算符进行重载

PS: C# 中 "?." 为不可重载运算符, 关于运算符重载请看官方文档

另外, Unity 中被 Destroy 的物体, Unity 为了在这种类型上存储信息, 在试图访问这些对象时提供更多信息将其设置为了Unity自定义的空类型. 这意味着在语言层面上, 其依然占据着内存并且为有效引用, 这就导致使用 "?." 的情况下判定为非空逻辑, 会正常调用 "?." 运算符后面的函数. 而这在 Unity 中是不被允许的, Unity会因此而报错.

MissingReferenceException: The object of type 'XXX' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.

优化思路

以上问题, 最通用的做法是先使用 == 或 != 运算符进行空值判断, 但还可以通过置空来实现目的.

优化基于两个目的:

  • 为了让两种判空类型的访问的结果一致
  • 为了提高判空效率. Unity重载后的判空效率比原生的要低

但其限制也非常明显

  • 能改变的仅限于自己的脚本且仅能改变脚本里的成员变量
  • 仅方法能使用 ?. 运算符.

我们可以在 Mono 脚本中的 OnDestroy 方法中将所有成员变量置空来实现目的. 最佳实践为继承自Mono 的单例类.

public class MonoManger<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T Instance => instance;

    protected virtual void Awake()
    {
        instance = this as T;
    }

    // 一般的单例类会在这里就结束书写了,但多加了这一句之后就方便了.
    protected virtual void OnDestroy()
    {
        instance = null;
    }
}

继承自此类的类型在获取单例对象的时候可以使用 ?. 判断执行方法.

进一步思考

以此类推, 将脚本中继承自 UnityEngine.Object 的对象在 OnDestroy 中置空就可以达到此目的, 但这样会非常麻烦, 所以如果我自己定义一个基类, 在 OnDestroy 中通过反射将类的所有成员变量置空, 就能非常方便的达到此目的了. 

参考文献:

C#语法糖 (?) null空合并运算符对UnityEngine.Object类型不起作用

Unity中使用C#的null条件运算符?.的注意事项

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值