getComponent 的方法实现接口。Unity C#

Method to getComponent implements interface. Unity C#

提问人:eClick_studio 提问时间:10/24/2022 最后编辑:eClick_studio 更新时间:10/24/2022 访问量:552

问:

我需要可以找到组件实现接口 T 的方法。 我有这个方法,但我无法正常工作。它应该像 TryGetComponent(out Interface interface) 一样工作。你能帮忙吗?

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;
}

如果我使用具体的接口,它会起作用:

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;
}
C# unity-game-engine 类型 接口 转换

评论


答:

0赞 user585968 10/24/2022 #1

代码的问题在于您正在尝试返回一个类型的类,但是约束定义为:TTType

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

...相当于:

public Type RaycastFindComponent(Type targetType) 

...这不是你想要的。

它应该显示(请注意,我们不再需要该参数):

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;
}


你基本上是想说哪个是苹果和橙子,结果失败了。TypeIMyInterface

评论

0赞 eClick_studio 10/24/2022
我理解。但是我想传递要找到的接口类型。在您的示例中,接口已写入方法签名中。
0赞 10/24/2022
T将是您要查找的具体类或接口。例如。该约束仅限制可以使用哪些类型。即它必须是一个组件,实现接口 IMyInterface 或派生。如果您总是要查找接口,则可以将 放入约束中。IMyInterfacewhereComponentwhere
0赞 eClick_studio 10/24/2022
public interface 接口 {} 调用应如下所示: _raycastHandler.RaycastFindComponent<Interface>();
0赞 10/24/2022
这是完全正确的。
0赞 eClick_studio 10/24/2022
但 IDE 会抛出异常:类型“Interface”不能用作泛型类型或方法“RaycastHandler.RaycastFindComponent”中的类型参数“T<T>()”。没有从“Interface”到“UnityEngine.Component”的隐式引用转换。
0赞 derHugo 10/24/2022 #2

它应该像 TryGetComponent(out Interface interface) 一样工作

因此,首先要将类型传入泛型,而不是将其实例作为参数!

其次,为了真正让它像TryGetComponent

  • 您想要使用参数并返回outbool
  • 为什么不实际使用支持接口的接口TryGetComponent

所以像这样的东西,例如

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;
}

该约束还包括接口,因为它们也是引用类型,因此可以(就像 Unity 的 / 一样)将任何类或接口作为泛型类型参数。classGetComponentTryGetComponent

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

当然,如果需要,你可以进一步限制它,但我会从最通用和可重用的方式开始,然后你仍然可以制作更受约束的版本