为什么 ReSharper 不建议对这两个块使用空传播?
Why does ReSharper not suggest using null propagation for both of these blocks?
ReSharper 建议对“易损坏”if 块使用空传播,但对于“forceVelocityCalculator”没有任何建议。
void Damage(Collider hitCollider)
{
var damageable = hitCollider.GetComponent<IDamageable>();
if (damageable != null)
{
damageable.TakeDamage(_damage);
}
}
void Push(Collider hitCollider)
{
var forceVelocityCalculator = hitCollider.GetComponent<ForceVelocityCalculator>();
if (forceVelocityCalculator != null)
{
forceVelocityCalculator.Push(_pushForce, GameAPI.playerTransform.transform.forward);
}
}
我错过了什么吗?我会为两个块使用空传播。
可能是因为 Unity 如何定义从 GetComponent()
返回的内容
如果你 真的 看看 GetComponent 做了什么,它实际上 never returns null
,你总是得到一个对象包装器来处理您的 C# 代码和 Unity 的底层 C++ 代码之间的通信。
因此,当您从 GetComponent()
中获得“null”时,您实际获得的 (Unity has overridden the ==
operator!) 实际上并不是 null,而是一个对象包装器 around一个null
。所以 ReSharper 不知道 null 传播在这里会有帮助(当然,假设它有效:因为对象不是 actually null,只是假装为 null,语法糖可能无法正常工作!)。
Unity 提供了关于此主题的 blog post,但随后是一个简短的摘要。
您的组件继承的 Unity 对象上的空值传播是不正确的。 Resharper 不建议这样做,Visual Studio 2019 对此发出警告。
为什么会出现 IDamageable
的建议?因为它是一个接口。 IDE(代码编辑器)不知道此接口实例的类型。它不知道 IDamageable
继承自 UnityEngine.Object
,因此不会出现提示。然而,ForceVelocityCalculator
继承自 MonoBehaviour
或 ScriptableObject
,两者均继承自 UnityEngine.Object
。
这很重要,因为 Unity 自定义了 ==
运算符。这样一来,你习惯的默认相等比较就不是这样了。
博客 post 给出了做出此决定的两个原因:
在编辑器中,Unity 有自己的 null 概念。 MonoBehaviour
的未初始化字段被赋予这个特定于 Unity 的空值。这与自定义 ==
运算符相结合,让 Unity 在您开发时为您(开发人员)提供额外的信息。您不会收到 NullReferenceException
和标准堆栈跟踪,而是收到增强的堆栈跟踪以及一些指示 GameObject
存在问题的指示。博客 posts 提到了一个巧妙的功能,它们在层次结构窗格中突出显示有问题的 GameObject
。
由于 Unity 是 C/C++ 引擎并且您使用 C# 编写脚本,因此您可以将 C# 对象 "wrapping" 视为 C++ 对象。有关该游戏对象的所有信息(附加组件、HideFlags 等)都在 C++ 对象中。此外,这些 C++ 对象的生命周期是明确管理的。这就是为什么您使用 Object.Destroy()
而不是将其设置为 null 的原因。自定义 ==
运算符解决了 C++ 对象已被销毁但 "wrapping" C# 对象仍然存在的情况。在这种情况下,CSharpObject == null
returns 为真,即使您的 C# 对象在技术上不为空。
ReSharper 建议对“易损坏”if 块使用空传播,但对于“forceVelocityCalculator”没有任何建议。
void Damage(Collider hitCollider)
{
var damageable = hitCollider.GetComponent<IDamageable>();
if (damageable != null)
{
damageable.TakeDamage(_damage);
}
}
void Push(Collider hitCollider)
{
var forceVelocityCalculator = hitCollider.GetComponent<ForceVelocityCalculator>();
if (forceVelocityCalculator != null)
{
forceVelocityCalculator.Push(_pushForce, GameAPI.playerTransform.transform.forward);
}
}
我错过了什么吗?我会为两个块使用空传播。
可能是因为 Unity 如何定义从 GetComponent()
返回的内容
如果你 真的 看看 GetComponent 做了什么,它实际上 never returns null
,你总是得到一个对象包装器来处理您的 C# 代码和 Unity 的底层 C++ 代码之间的通信。
因此,当您从 GetComponent()
中获得“null”时,您实际获得的 (Unity has overridden the ==
operator!) 实际上并不是 null,而是一个对象包装器 around一个null
。所以 ReSharper 不知道 null 传播在这里会有帮助(当然,假设它有效:因为对象不是 actually null,只是假装为 null,语法糖可能无法正常工作!)。
Unity 提供了关于此主题的 blog post,但随后是一个简短的摘要。
您的组件继承的 Unity 对象上的空值传播是不正确的。 Resharper 不建议这样做,Visual Studio 2019 对此发出警告。
为什么会出现 IDamageable
的建议?因为它是一个接口。 IDE(代码编辑器)不知道此接口实例的类型。它不知道 IDamageable
继承自 UnityEngine.Object
,因此不会出现提示。然而,ForceVelocityCalculator
继承自 MonoBehaviour
或 ScriptableObject
,两者均继承自 UnityEngine.Object
。
这很重要,因为 Unity 自定义了 ==
运算符。这样一来,你习惯的默认相等比较就不是这样了。
博客 post 给出了做出此决定的两个原因:
在编辑器中,Unity 有自己的 null 概念。
MonoBehaviour
的未初始化字段被赋予这个特定于 Unity 的空值。这与自定义==
运算符相结合,让 Unity 在您开发时为您(开发人员)提供额外的信息。您不会收到NullReferenceException
和标准堆栈跟踪,而是收到增强的堆栈跟踪以及一些指示GameObject
存在问题的指示。博客 posts 提到了一个巧妙的功能,它们在层次结构窗格中突出显示有问题的GameObject
。由于 Unity 是 C/C++ 引擎并且您使用 C# 编写脚本,因此您可以将 C# 对象 "wrapping" 视为 C++ 对象。有关该游戏对象的所有信息(附加组件、HideFlags 等)都在 C++ 对象中。此外,这些 C++ 对象的生命周期是明确管理的。这就是为什么您使用
Object.Destroy()
而不是将其设置为 null 的原因。自定义==
运算符解决了 C++ 对象已被销毁但 "wrapping" C# 对象仍然存在的情况。在这种情况下,CSharpObject == null
returns 为真,即使您的 C# 对象在技术上不为空。