Home > Enterprise >  Method to getComponent implements interface. Unity C#
Method to getComponent implements interface. Unity C#

Time:10-25

I need method that can find component implements interface T. I have this method but i does not work correctly. It should work like TryGetComponent(out Interface interface). Can you help?

public T RaycastFindComponent<T>(T targetType) where T : Type
{
    RaycastHit2D[] raycastHits = Physics2D.RaycastAll(_mainCamera.ScreenToWorldPoint(Input.mousePosition), new Vector2());
    foreach (RaycastHit2D raycastHit in raycastHits)
    {
        foreach (MonoBehaviour component in raycastHit.transform.GetComponents(typeof(MonoBehaviour)))
        {
            Type componentType = component.GetType();
            Debug.Log($"GetComponent = {componentType is T}"); //true
            if (componentType is T)
            {
                return component as T; //null but (componentType is T = true)
            }
        }
    }
    return null;
}

It works if I use concrete Interface:

public Interface RaycastFindComponent()
{
    RaycastHit2D[] raycastHits = Physics2D.RaycastAll(_mainCamera.ScreenToWorldPoint(Input.mousePosition), new Vector2());
    foreach (RaycastHit2D raycastHit in raycastHits)
    {
        foreach (MonoBehaviour component in raycastHit.transform.GetComponents(typeof(Interface)))
        {
            Type componentType = component.GetType();
            Debug.Log($"GetComponent = {componentType is Interface}"); //true
            if (componentType is T)
            {
                return component as Interface; //(Interface)component
            }
        }
    }
    return null;
}

CodePudding user response:

The problem with your code is that you are trying to return a class of type T however the T constraint is defined as Type:

public T RaycastFindComponent<T>(T targetType) where T : Type

...is equivalent to:

public Type RaycastFindComponent(Type targetType) 

...which isn't what you want.

It should read (note we don't need the parameter anymore):

public T RaycastFindComponent<T>() where T : Component, IMyInterface // NEW
{
    var targetType = typeof(T); // <--- NEW

    RaycastHit2D[] raycastHits = Physics2D.RaycastAll(_mainCamera.ScreenToWorldPoint(Input.mousePosition), new Vector2());
    foreach (RaycastHit2D raycastHit in raycastHits)
    {
        foreach (MonoBehaviour component in raycastHit.transform.GetComponents(targetType))
        {
            if (component is T)
            {
                return component as T; 
            }
        }
    }
    return null;
}


You were essentially trying to cast Type to say IMyInterface which is apples and oranges and thus fails.

CodePudding user response:

It should work like TryGetComponent(out Interface interface)

So first of all you want to pass in the type into the generic, not additionally an instance of it as a parameter!

Then secondly in order to really make it work like TryGetComponent

  • You want to use an out parameter and return bool
  • Why not actually use TryGetComponent which does support interfaces

so something like e.g.

public bool RaycastFindComponent<T>(out T result) where T : class
{
    var raycastHits = Physics2D.RaycastAll(_mainCamera.ScreenToWorldPoint(Input.mousePosition), new Vector2());

    foreach (RaycastHit2D raycastHit in raycastHits)
    {
        if (raycastHit.transform.TryGetComponent<T>(out result))
        {
            return true;
        }
    }

    result = default;
    return false;
}

The constraint class also includes interfaces since they are also reference-type so this can (just like Unity's GetComponent / TryGetComponent) take any class or interface as the generic type parameter.

if(RaycastFindComponent<ISomeInterface>(out var instance))
{
    Debug.Log("You hit {instance}", instance);
}

of course you could constrain it further down if needed, but I would start with the most generic and re-usable way and then you can still make more constrained versions of it

  • Related