“Null object not being null” 可翻译为 “空对象不为 null”。

huangapple go评论47阅读模式
英文:

Null object not being null

问题

Here's the translated code:

我编写了以下函数,用于在我的Unity项目中进行健全性检查时提供便捷的工具

namespace MyProject.Utilities
{
    public class DebugUtils
    {
        /// <summary>
        /// 检查传递的对象是否为null,如果是,则打印到控制台。
        /// </summary>
        /// <param name="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}] 类型为 {typeof(T)} 的对象在方法 {methodName} 中为null,位于 {fileName}:{lineNumber}";
                UnityEngine.Debug.Assert(false, message);
            }
        }
    }
}

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

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

请注意,翻译结果中只包含代码部分,没有其他内容。

英文:

I wrote the following function to have a handy utility for sanity checks in my unity projects.

namespace MyProject.Utilities
{
    public class DebugUtils
    {
        /// &lt;summary&gt;
        /// Checks if passed object is null and prints to console if it is.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;obj&quot;&gt;The obj.&lt;/param&gt;
        public static void DebugAssertNull&lt;T&gt;(T obj, string tag = &quot;M_UTILS_DEBUG&quot;)
        {
            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 = $&quot;[{tag}] Object of type {typeof(T)} is null in method {methodName} at {fileName}:{lineNumber}&quot;;
                UnityEngine.Debug.Assert(false, message);
            }
        }
    }
}

Now when I call this function from another script as follows

public class SomeBehaviour: MonoBehaviour{
    public GameObject someObject;
    
    void Start(){
        DebugAssertNull&lt;GameObject&gt;(someObject);
    }

}

Now I am expecting that a message prints to the console. However upon running this code obj turns out to be not null. Using the debugger in Visual Studio 2019, setting up a watch obj == null evaluates to true.

I feel like there is some implementation detail I am missing here. I am working with unity 2021, Visual Studio 2019, and .NET Framework 4.

答案1

得分: 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);
    }
}

这种方式肯定会使用重载的 UnityEngine.Object ==

如果这意味着要用于 Unity Inspector 中引用的内容,那么这就足够了。

在 Inspector 中唯一按引用传递的东西就是 UnityEngine.Object。其他一切都作为值直接反序列化,永远不会为 null

然后问题可能是,为什么要为这种情况使用这样的调试工具,而不是直接检查,如下所示:

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

这样做的好处是:

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

Just in addition to this answer.

Since your method uses generics without any type limitation it will use the most generic == implementation which is for System.Object.

It works as expected if you explicitly limit the type like e.g.

public static void DebugAssertNull&lt;T&gt;(T obj, string tag = &quot;M_UTILS_DEBUG&quot;) 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 = $&quot;[{tag}] Object of type {typeof(T)} is null in method {methodName} at {fileName}:{lineNumber}&quot;;
        UnityEngine.Debug.Assert(false, message);
    }
}

This way it definitely uses the overload UnityEngine.Object ==.

If this is intended to be used for stuff referenced in the Unity Inspector it should also be enough.

The only thing going by reference in the Inspector is UnityEngine.Object. Everything else is deserialized as values directly and never null.

Question would then be though why have such a debug tool for this case instead of simply checking directly

private void Start()
{
    if(!someObject) Debug.LogError($&quot;{nameof(someObject)} is not assigned&quot;, this);
}

advantage of this would be:

  • Double click on the log message and directly jump to according code line
  • Click once on the message highlights according object in the Hierarchy (or the assets)

答案2

得分: 1

这是一个古老的Unity... 嗯... 让我们称之为一个“特性” =)

原因是真正的Unity对象在C++部分,而C#对象只是这些对象的包装器。这就是为什么基本的Unity3d对象重写了 == 运算符,并在与空值比较时返回 true,即使对象仍然存在。

你可以在这里找到更多信息

英文:

It's an old Unity... hmm... let's call it a "feature" =)

The reason is that real Unity objects are in the C++ part and C# objects are only wrappers for these objects. That's why the basic Unity3d object overrides == operator and returns true in case of comparing with null even object still exists.

You can find more information here

huangapple
  • 本文由 发表于 2023年5月11日 15:45:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76225216.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定