Why does ReSharper not suggest using null propagation for both of these blocks?

China☆狼群 提交于 2021-02-04 18:05:43

问题


ReSharper suggests using null propagation for the "damageable" if block, but for the "forceVelocityCalculator" one there is no suggestion.

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);
    }
}

Am I missing something? I would use null propagation for both blocks.


回答1:


Unity offers a blog post about this topic, but a short summary follows.

Null propagation on Unity objects, which your components inherit from, is incorrect. Resharper doesn't suggest doing it and Visual Studio 2019 gives a warning about it.

Why does the suggestion occur for IDamageable? Because it's an interface. The IDE(code editor) doesn't know the type for an instance of this interface. It can't know that IDamageable inherits from UnityEngine.Object, so no suggestion occurs. ForceVelocityCalculator, however, inherits from MonoBehaviour or ScriptableObject, both of which inherit from UnityEngine.Object. This is significant because Unity has customized the == operator. In this way, the default equality comparison you're used to is not what happens.

The blog post gives two reasons for this decision:

  1. Within the Editor, Unity has its own concept of null. Uninitialized fields of a MonoBehaviour are given this Unity-specific null value. This, combined with a custom == operator, lets Unity provide additional information to you, the developer, while you develop. Instead of receiving a NullReferenceException and standard stack trace, you instead receive an enhanced stack trace plus some indication of which GameObject the problem exists for. The blog posts mentions a neat feature where they highlight the problematic GameObject within the Hierarchy pane.

  2. Since Unity is a C/C++ engine and you write scripts in C#, you can think of your C# objects "wrapping" the C++ objects. All of the information about that GameObject (attached components, HideFlags, etc) are in the C++ object. Also, the lifetime of these C++ objects is explicitly managed. It is why you use Object.Destroy() instead of setting things to null. The custom == operator solves the scenario where a C++ object has been destroyed but the "wrapping" C# object still lives. In this case, CSharpObject == null returns true, even though your C# object technically is not null.




回答2:


Probably because of how Unity has defined what comes back from GetComponent()

If you really really look at what GetComponent does, it actually never returns null, you always get an object wrapper that handles the communication between your C# code and Unity's underlying C++ code.

So when you get "null" from GetComponent() what you actually get (Unity has overridden the == operator!) is not actually null, but an object wrapper around a null. So ReSharper doesn't know that null propagation would be helpful here (assuming, of course, that it works: because the object isn't actually null, just pretending to be null, the syntactic sugar might not work properly!).



来源:https://stackoverflow.com/questions/58487442/why-does-resharper-not-suggest-using-null-propagation-for-both-of-these-blocks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!