英文原文:https://nosuchstudio.medium.com/why-are-null-coalescing-operators-evil-in-unity-16f5a88d6071
我最近在 C# 中遇到了空合并运算符。 如果您不熟悉它们,以下是它们的工作原理。
?? 如果不为空,则返回左侧,否则返回右侧。 举个例子:
public void ProcessFunc(List<int> myList) {
var processList = myList ?? new List<int>();
}
如果 myList 为 null,此行会将 processList 设置为新列表。
??= 只是 ?? 的赋值变体 。
List<int> myList;
void Awake() {
myList ??= new List<int>();
}
仅当 myList 为空时,此行才会将其设置为新列表。
空合并运算符非常适合初始化类。 如果您想了解更多信息,请阅读 Microsoft 的文档。
在 Unity 中,执行 null 检查并基于它们进行分配是一种常见模式。 一个被空合并运算符取代的完美模式!
SpriteRenderer sr;
if (sr == null) sr = GetComponent<SpriteRenderer>();
// 我们应该用下面的一行替换上面的一行吗?
sr ??= GetComponent<SpriteRenderer>();
我开始使用空合并运算符而不是空检查,很快我的代码中出现了一些非常讨厌的错误。 有时?? 即使空检查将返回 true,运算符也会返回左侧! 上面两行会产生不同的结果!
那么这是怎么回事呢?
事实证明,Unity 重载了“Unity.Object”类型(任何派生自 UnityEngine.Object 的类型)的 == 运算符。 这就是当游戏对象被销毁时变量变成 null 的原因。 在 C# 中将变量分配为 null 几乎是不可能的。 因此,Unity 工程师决定重载空检查。
空合并运算符始终检查引用是否相等,从而检查结果的差异。 对于被销毁的 GameObject,即使其实际值不为 null,引用也等于 null。
一个简单的解决方案是超载 ?? 和 ??= Unity 对象的运算符。 不幸的是,C# 不允许重载这些运算符。 所以没有简单的方法来解决这个问题。
我们是怎么来到这里的? 是谁的错?
Unity 工程师很早就知道这一点。 2014 年的一篇 Unity 博客文章展示了他们如何考虑摆脱相等性检查覆盖。 但显然他们决定不中断所有 Unity 项目,以实现更光明的未来。
至少可以说,重载相等运算符有点不确定,但如果不是后来引入的新空合并运算符,这仍然是一个不错的决定。
对于这种情况,Microsoft 的 C# 工程师至少应该承担部分责任(读作责备),因为他们让开发人员重载了相等运算符而不是空合并运算符。
我不知道为什么 C# 不允许这样做。 我怀疑它使 C# 保持干净和可预测。
好吧,但是我该怎么办呢?
尽管新的空合并运算符很闪亮,但它们只是一些语法糖,例如 ? : 三元运算符。 只要避免使用它们,坚持简单的 == 检查就可以了。 很抱歉向您宣传这些运算符并告诉您不要立即使用它们。 生活并不完美。
尾注
我是一名软件工程师转为游戏开发人员。 我定期发布有关我在 Unity 中面临的挑战的文章,并在这里分享我的经验。 关注我的社交媒体,了解使用 Unity、C# 进行游戏开发并聆听我的故事。