1
\$\begingroup\$

In the following code, when T is Rigidbody, calling componentToLookIn.GetComponent<T>() returns "null" when there is no rigidbody attached, instead of simply null:

public static class ComponentExtensions { public static bool TryFindComponent<T>(this Component componentToLookIn, out T componentToLookFor) { componentToLookFor = componentToLookIn.GetComponent<T>(); return componentToLookFor != null; } } 

Here is the debug window:

enter image description here

As a result, componentToLookFor != null ends up being true, which is obviously not what I want.

When I invoke componentToLookIn.GetComponent<T>() where T is NOT Rigidbody, null is returned as expected when there is no component of type T found.

What is so special about components of the Rigidbody type that GetComponent<Rigidbody>() behaves differently?

EDIT:

For contrast, here is the debug window when GetComponent<BoxCollider>() is invoked on a game object that does not have any component of the type BoxCollider: enter image description here

As you can see, the value of childComponent is simply null, not "null". componentToLookFor != null therefore returns false.

\$\endgroup\$
7
  • \$\begingroup\$ If it is a string it would say so in the type, no? Are you sure you aren't calling this method more often and are looking at the wrong call? \$\endgroup\$ Commented Mar 13, 2018 at 14:51
  • \$\begingroup\$ Possible duplicate of How to make an Assert.IsNull test pass when the value is reported as <null>? \$\endgroup\$ Commented Mar 13, 2018 at 14:54
  • \$\begingroup\$ @Sidar I am 100% certain that I am looking at the correct call. I have updated my question to include more details. \$\endgroup\$ Commented Mar 13, 2018 at 14:59
  • \$\begingroup\$ Every time you try to GetComponent<T>() on a game object that doesn't have that T component, Unity return that pseudo-null indicated by "null", as suggested by Tyyppi_77. Can you post the code that calls the extension method in the case of the rigidbody and the boxcollider? \$\endgroup\$ Commented Mar 13, 2018 at 15:08
  • \$\begingroup\$ Did the object never have this component attached, or was it attached then destroyed? \$\endgroup\$ Commented Mar 13, 2018 at 15:08

1 Answer 1

3
\$\begingroup\$

This happens only when running in the Unity editor, and only with certain built-in component types.

In a release build, GetComponent<T>() always returns null if the GameObject does not have a component of type T attached.

When running inside the Unity Editor, GetComponent<Rigidbody>() instead returns a Rigidbody component that's been marked as a "stub" - an empty reference that perhaps the developer forgot to wire-up in the inspector. (It's not the string "null", that's just how it's configured to print when represented as text)

For these, Unity's overridden == operator for types deriving from UnityEngine.Object will return true when comparing to null (similar to what happens if you hold onto a reference to a component after it/its GameObject has been destroyed).

But the fact that it's not really null lets Unity offer more descriptive error messages, like...

  • "Unassigned Reference Exception" (Inspector field not populated)
  • "Missing Component Exception" (GetComponent<> with no matching component attached)
  • "Missing Reference Exception" (Component has been destroyed)

So, if Unity's == is overridden to compare as equal to null in this case, why doesn't your null check work?

Because your generic method doesn't know that T is a Component, so it doesn't know to apply Unity's overridden operator.

To solve this and get consistent null detection between Editor and builds, you can add a where T : Component type constraint to your method, or cast your reference to a Unity type like a component first, then do your comparison with that.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for your very informative answer! I suppose another alternative is to change my return statement to return !childComponent.Equals(null);? \$\endgroup\$ Commented Mar 15, 2018 at 8:54

You must log in to answer this question.