Unity——关于UnityEngine.Object的判空

xiaoxiao2025-08-09  27

开始

先看一段代码:

using UnityEngine; public class UnityEngineObjectCheck : MonoBehaviour { void Start () { GameObject go1 = new GameObject ("go1"); GameObject go2 = new GameObject ("go2"); DestroyImmediate (go1); Debug.Log ("go1 == null : " + (go1 == null).ToString()); Debug.Log ("go2 == null : " + (go2 == null).ToString()); GameObject go = go1 ?? go2; Debug.Log ("go == null : " + (go == null).ToString()); } }

代码中,先创建了两个GameObject:go1和go2;接下来立即将go1销毁;然后将go1和go2分别与null比较的结果打印出来;最后通过??运算符得到返回值并赋值给go,并输出go与null比较的结果。

不了解??运算符的可以看看MSDN,这里是传送门。

直觉上: 1、go1被销毁了,那么第一个输出将是go1 == null : True; 2、没有对go2进行操作,那么第二个输出应该是go2 == null : False; 3、通过??运算符、go1既然是null、那么go将会被赋值为go2。因此第三个输出将是go == null : False。

实验

测试之。将脚本挂在场景中任意物体,运行后发现输出结果与前面推测的不太一致: 问题主要表现在第三个输出上。通过该结果,可以断定,go被赋值为go1。也就是说,go1实际的值是“非null”的(虽然输出看起来是null)。

分析

分析GameObject的继承关系,GameObject继承自UnityEngine.Object。查看UnityEngine.Object的类结构,发现UnityEngine.Object重写了==运算符和!=运算符。因此可以猜测,当执行DestroyImmediate后,go1并不是真正就是null了,只是使用==运算符和!=运算符时,Unity会把它当作null值处理。Unity真正将go1置空的时机就不得而知。

// // Operators // public static bool operator == (Object x, Object y); public static bool operator != (Object x, Object y);

这么做在Unity中是合理的,因为我们在Unity中做开发的时候,被Destroy掉的对象,就应当被认为它的值是null。然而,在使用Lua对Unity对象进行空值判定的时候,就会出现问题了。

在Unity+XLua中的实验

接下来的实验在Unity+XLua的环境中进行。 当使用Unity执行如下的Lua代码时,会得到go == nil : false的结果。

local go = CS.UnityEngine.GameObject('go') CS.UnityEngine.GameObject.DestroyImmediate(go) print('go == nil : ', go == nil)

这里的表现与直接在Unity中进行空值判定是不一致的,同时也是不合理的。因为我们很有可能会有如下类似的操作:

if go ~= nil then --Some action like [go.name = 'go1'] or other end

此时会报出以下错误: 这不是我们希望看到的结果。所以在Lua中,并不能用go ~= nil来直接对UnityEngine.Object的对象进行判空。

解决方案

为了统一Unity侧和Lua侧的判空行为,我们可以对UnityEngine.Object进行扩展,使其可以提供一个方法来供Lua侧调用,进而保持Lua侧和Unity侧判空行为的一致。

在Unity中新建脚本UnityEngineObjectExtensionForXLua.cs并写入以下代码:

using UnityEngine; public static class UnityEngineObjectExtensionForXLua { /// <summary> /// 用于UnityEngine.Object及其子类对象的判空 /// 在使用DestroyImmediate销毁一个UnityEngine.Object对象时,该对象会被Unity认为已经是null /// 但是C#并不认为它是null /// 因此在与Lua交互时,不能直接在Lua侧判断对象是否为nil(这样判断走的是C#的判空),应该调用此方法(走的是Unity的判空) /// </summary> public static bool IsNull(this Object target) { return target == null; } }

在Lua侧提供一个工具函数IsNull,代码如下:

function IsNull(unityObject) if unityObject == nil then return true end if type(unityObject) == 'userdata' and unityObject.IsNull ~= nil then return unityObject:IsNull() end return false end

之后,在Lua侧需要对UnityEngine.Object对象进行空值判定时,使用此函数即可。当然,该函数也兼容Lua侧对象。

转载请注明原文地址: https://www.6miu.com/read-5034567.html

最新回复(0)