关于XLua中GameObject返回值不为nil的思考

文章目录[x]
  1. 1:问题描述
  2. 2:官方解决办法
  3. 3:原因探究
  4. 4:注意
  5. 5:参考

问题描述


在Lua中,判定一个变量是否为空采用的是 if var == nil then end 的方式,但是假如这里的 var 是继承自 UnityEngine.Object 那么此代码则无法按照我们所期望的流程执行,例如 GameObjectComponent

 

官方解决办法


一种解决方法就是在C#里写一个判空的扩展方法供lua调用,如下

public static class UnityEngineObjectExtention
{
    public static bool IsNull(this UnityEngine.Object o)
    {
        return o == null;
    }
}

 

原因探究


出现这种现象的原因就是,XLua 在其 LuaDLL 中维护了一个nil表。当使用 var == nil 或者 if var then end 时,xlua会从此表中查找(调用LuaDLL.Lua.lua_isnil() 来判断),此API在 LuaDLL.cs 中。那么什么时候push进这个表呢?以component举例,就是当我们使用 GetComponent<> 时,在C#中会对返回结果进行 null 判断,当为null时,就 push 进 nil 表。如下图:


注意:此方法在 ObjectTranslator.cs 中,有多个重载。有多个重载。有多个重载。这里就不一一放上来了。请读者自行查看。

而GameObject和Component之所以能用 == 直接判空,是因为Unity对 UnityEngine.Object 做了运算符重载的操作,
而这里的 LuaBase 是一个 System.Object,所以会出现使用 == 判空失效的情况。那么什么时候会失效呢?带着疑问往下看,

疑问:即使使用的是System.Object的判空 那当一个变量为null时, xx==null 也应该能判断正确,为什么到了这里就不正确了呢?

实践:

1.在lua中获取一个组件并打好断点

2.在UnityEngineGameObjectWrap.cs中的 _m_GetComponent 中打好断点

3.运行游戏

可以看到,这里的我们获取的 Component 变成了System.Object,并且是一个未初始化的 System.Object,所以它并不为null。

而真正的null应该如下图显示的一样。

 

此时如果修改代码:

 

再运行游戏,会发现在 Lua 中也能对 GameObject 和 Component 使用 nil 判空啦。

 

注意


虽然通过修改源代码可以实现,使用 nil 对 GameObject 和 Component 判空,但是在项目中我们仍使用官方推荐的方式。(毕竟修改代码这种方式XLua的作者肯定能想到,但是作者没有这样写,也许有人家的道理吧)

 

参考


xLua下调用GetComponent时返回值不是nil的坑
有的Unity对象,在C#为null,在lua为啥不为nil呢?比如一个已经Destroy的GameObject

 

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像