我有一个特殊的函数,它可以将一个对象
作为参数。这样它就可以是 MonoBehaviour 或 GameObject:
奇怪的是,当我将 null GameObject
转换为 Object
时,它不再显示为 null:
public class EquipmentSlots : MonoBehaviour {
// This is null: it hasn't been set in the inspector
public GameObject offHandEquipLocation;
void Start () {
Validation.RequireField(
"offHandEquipLocation",
offHandEquipLocation
)
}
}
public class Validation : MonoBehaviour {
public static void RequireField(string name, object field) {
if (field == null) {
Debug.Log($"{name} field is unset");
}
}
}
Log
调用永远不会在这里运行,因为该对象不为空。
如果我将 Debug.Log(offHandEquipLocation == null)
放在 Start()
函数中,它会打印 true
。如果我将 Debug.Log(field == null)
放在 RequireField()
方法中,它会打印 false
。
有什么方法可以查看对象
是否为空?
最佳答案
一般来说,第一个想法是:不要这样做 ^^
这有一个问题:您更改了调用的堆栈跟踪。当您在控制台中看到错误时,通过将 null 检查传递给静态类,您以前无法像以前那样直接看到它从哪里抛出/记录,通过双击它直接转到相应的代码行,但不能(这很容易) 在层次结构中突出显示相应的对象“上下文”。
所以我总是会尽可能地让检查接近实际使用情况,而不是像这样做
if(!offHandEquipLocation) Debug.LogError($"{nameof(offHandEquipLocation)} is not referenced!", this);
Debug.Log
的整体意义是让您在调试时更轻松 ;) 使用上述方法比使用您的方法不必键入 Debug.LogError($"{nameof(offHandEquipLocation)} 未被引用!", this);
多次。
正如其他人和我已经提到的,它无法按预期工作的原因是 Unity 的 custom == null
类型的 Object
行为,大多数内置类型特别是 GameObject
、ScriptableObject
和 Component
继承。
即使 Object
“可能看起来是”或更好地说返回一个值等于 null
的值,Unity 实际上仍然在引用中存储一些元信息为了抛出自定义异常(MissingReferenceException
、MissingComponentException
、UnassignedReferenceException
),这些异常比简单的NullReferenceException
(你也可以看到 here )。因此,它在底层 object
类型中实际上不是 null
。
一旦将其转换为 object
,自定义 == null
行为就消失了,但底层的 object
仍然存在,因此您得到字段 == null
→ false
然而,一个解决方案可能是使用 bool
operator 为 Object
创建一个简单的重载。这取代了 null
检查,意味着类似于 This object is referenced, exists, and was not destroyed yet.
。并继续使用 == null
做其他事情
public static void RequireField(string name, object field)
{
if (field == null) Debug.LogError($"{name} field is unset");
}
public static void RequireField(string name, Object field)
{
if (!field) Debug.LogError($"{name} field is unset");
}
现在您可以同时使用两者。需要注意的是:我不会使用口头的 string
作为第一个参数,而是总是使用 nameof
传递它,以使其更安全地重命名
var GameObject someObject;
var string someString;
Validation.validate(nameof(someObject), someObject);
Validation.validate(nameof(someString), someString);
关于您在例如字符串
一般:
一旦这是检查器中任何组件
的public
或[SerializedField]
字段(MonoBehaviour
) 或 ScriptableObject
它总是由 Unity Inspector 本身使用默认值初始化。因此,对任何例如
public int intValue;
[SerializeField] private string stringValue;
public Vector3 someVector;
public int[] intArray;
...
是多余的,因为它们都不会是 null
。这也适用于任何可序列化类型,因此即使您有自定义类也是如此
[Serializable]
public class Example
{
public string aField;
}
然后在您的行为中使用序列化字段,例如
public List<Example> example;
而且这个永远不会是null
。
顺便说一句,正如已经提到的那样,Validation
不应该继承自 MonoBehaviour
而应该是
public static class Validation
{
// only static members
...
}
关于c# - 当我转换为对象时,null GameObject 变为非空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58068696/