HasComponent

0
down vote
favorite

So I am writing a method to check if a gameObject has a component.

Here it is:

public static bool HasComponent (this GameObject obj)
{
    return obj.GetComponent<T>() != null;
}

And I’m using it like this:

void Update()
{

    if (Input.GetKey("w"))
    {
        if (gameObject.HasComponent<Rigidbody>())
        {
            print("Has a rigid body.");
            return;
        }

        print("Does not have rigid body.");
    }
}

The gameObject does NOT have a rigid body but it is still printing that it does have.

Well, i guess your method definition looks like this:

 public static bool HasComponent<T> (this GameObject obj)
 {
     return obj.GetComponent<T>() != null;
 }

in which case you run into a nasty edge case problem. In the past this definition wouldn’t compile since GetComponent used to have a contraint on the generic parameter to only allow types derived from Component.

Unity seem to have changed the definition and removed the constraint. This allows us to also use interfaces which is great.

However in your case the problem (which only occurs in the editor btw) is, that the “!=” check in your generic method most likely does a “System.Object” comparison. When testing inside the editor GetComponent will always return an instance. However that instance usually pretends to be null. This is done by overloading the “UnityEngine.Object” “==” and “!=” operators. Since your generic method doesn’t use that specific operator it actually sees that fake-null object which of course is not null.

The problem shouldn’t occur in a built version of your game.

There are several ways to make it work inside the editor as well:

First, add a constraint to “Component”:

 public static bool HasComponent<T> (this GameObject obj) where T : Component
 {
     return obj.GetComponent<T>() != null;
 }

this will make the generic method to use the overloaded operators. However doing so prevents you from using interfaces with your method.

Another way would be to simply do an “as-cast” to ensure the right type:

 public static bool HasComponent<T> (this GameObject obj)
 {
     return (obj.GetComponent<T>() as Component) != null;
 }

This should work with all cases.

Another one would be

 public static bool HasComponent<T> (this GameObject obj)
 {
     return obj.GetComponent(typeof(T)) != null;
 }

The System.Type version of GetComponent always returns a Component. Since you don’t use the actual type it’s not necessary to use the generic version.

Try using if(Input.GetKeyDown(“W”))

the function definition is still missing the <T> in …

public static bool HasComponent (this GameObject obj)

plus you possibly want constraints too (which should prevent invalid calls like HasComponent<int>()) and have it also extend Component instead to let pretty much anything that has a GetComponent<T>() have this function too

 public static bool HasComponent<T> (this Component obj) where T:class

So it worked perfectly when I replaced the

where T : class

//With

where T : Component