问题:
报错LuaException: invalid arguments to IsNull
只存在于包体,未存在于编辑器
解决思路:
一开始在lua中探索很久,想找到lua中存储的uobj为什么会为空,但探查下去并没发现本人的代码和他人的代码有什么独特之处,又因为项目组几天前更新引擎,遂从底层一点的角度开始考虑。
在全部文件中全局搜索”invalid arguments to “,发现只存在于MethodWrapsCache的public int Call(RealStatePtr L)中,简单溯源后,发现这是xlua的反射调用到的。
但问题是,IsNull这个方法,经由扩展方法,已经被放到了UnityEngineObjectWrap中,Utils.RegisterFunc(L, Utils.METHOD_IDX, “IsNull”, _m_IsNull);
那为什么会走到反射部分的代码?会不会是因为走到反射部分的代码,才导致的bug?
于是,想尝试注释掉xluaConfig中的typeof(UnityEngine.Object),Regenerate一下xlua。(结果发现xluaConfig根本没有typeof(UnityEngine.Object),是因为项目组管理引擎的同学在新版本不小心删除掉了这项)
重新生成后的xlua,在编辑器下成功复现了包体上的问题。
至此,编辑器下与包体表现不同的原因找到了————编辑器下的xluaConfig文件不对,但是生成的文件都是对的(为什么会这样,我的猜测是这个同学一开始误删了typeof(UnityEngine.Object)并加了回来,但后续加回来的时候,只提交了生成文件,没有提交这个config)。
由于我们打包的时候,会重新根据xluaConfig生成xlua相应的文件,这就导致了包体里面的xlua和实际上unity的不同,也就导致了二者的显示不同。
那为什么wrap不报错,反射却报错?
因为是静态扩展方法,所以即使是null的C#对象,也可以调用public static bool IsNull(this UnityEngine.Object o),只不过o作为了null传了进去。但是在反射时,会先进行类型检查————很明显null是过不去类型检查的,于是就走到了这一行的报错LuaAPI.luaL_error(L, “invalid arguments to ” + methodName);
至此,终结!
思考:
不过问题的核心,可能还是,lua的业务层不应该对一个引用对象已经失效的lua的userdata(也就是持有的uobj)进行方法的调用。其实这也是很神奇的,local uobj, uobj不为null,但是它的userdata指向的C#其实已经被回收了,所以调用IsNull这个方法会出问题。为什么会出现这种情况呢?还在查啦。