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 returnbool
- 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