空对象不为空

Piy*_*kar 1 c# unity-game-engine

我编写了以下函数,以便在我的统一项目中提供一个方便的实用程序来进行健全性检查。

namespace MyProject.Utilities
{
    public class DebugUtils
    {
        /// <summary>
        /// Checks if passed object is null and prints to console if it is.
        /// </summary>
        /// <param name="obj">The obj.</param>
        public static void DebugAssertNull<T>(T obj, string tag = "M_UTILS_DEBUG")
        {
            if (obj == null) 
            {
                StackTrace stackTrace = new();
                StackFrame stackFrame = stackTrace.GetFrame(1);
                string methodName = stackFrame.GetMethod().Name;
                string fileName = stackFrame.GetFileName();
                int lineNumber = stackFrame.GetFileLineNumber();
                string message = $"[{tag}] Object of type {typeof(T)} is null in method {methodName} at {fileName}:{lineNumber}";
                UnityEngine.Debug.Assert(false, message);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我从另一个脚本调用这个函数时,如下所示

public class SomeBehaviour: MonoBehaviour{
    public GameObject someObject;
    
    void Start(){
        DebugAssertNull<GameObject>(someObject);
    }

}
Run Code Online (Sandbox Code Playgroud)

现在我期待一条消息打印到控制台。然而,运行此代码后,结果 obj 不为空。使用 Visual Studio 2019 中的调试器,设置监视 obj == null的结果为 true。

我觉得这里缺少一些实现细节。我正在使用 unity 2021、Visual Studio 2019 和 .NET Framework 4。

der*_*ugo 5

只是除了这个答案

由于您的方法使用泛型而没有任何类型限制,因此它将使用最通用的==实现,即System.Object.

如果您明确限制类型,例如,它会按预期工作

public static void DebugAssertNull<T>(T obj, string tag = "M_UTILS_DEBUG") where T : UnityEngine.Object
{
    if (obj == null) 
    {
        StackTrace stackTrace = new();
        StackFrame stackFrame = stackTrace.GetFrame(1);
        string methodName = stackFrame.GetMethod().Name;
        string fileName = stackFrame.GetFileName();
        int lineNumber = stackFrame.GetFileLineNumber();
        string message = $"[{tag}] Object of type {typeof(T)} is null in method {methodName} at {fileName}:{lineNumber}";
        UnityEngine.Debug.Assert(false, message);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样它肯定会使用重载UnityEngine.Object ==

如果这打算用于 Unity Inspector 中引用的内容,那么它也应该足够了。

检查器中唯一引用的内容 UnityEngine.Object. 其他所有内容都会直接反序列化为值,并且永远不会null

那么问题是为什么在这种情况下需要这样的调试工具而不是简单地直接检查

private void Start()
{
    if(!someObject) Debug.LogError($"{nameof(someObject)} is not assigned", this);
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处是:

  • 双击日志消息,直接跳转到相应的代码行
  • 单击消息突出显示层次结构中的相应对象(或资产)