ReSharper suggests using null propagation for the "damageable" if block, but for the "forceVelocityCalculator" one there is no suggestion.
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:
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.
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.
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!).