调用带有参数化参数的方法

huangapple go评论98阅读模式
英文:

Invoking methods with parametrized arguments

问题

我目前正在构建一个事件系统来处理我应用程序中的一些事件。EventDispatcher 调用带有参数的方法,这些参数可以从事件的类中赋值。对于非参数化的参数,这可以正常工作,但我找不到解决办法来处理带有参数化参数(具有通用类型的参数)。我该如何筛选出这些参数呢

这里是我 Dispatcher 的一个小片段:

private final Event event; // 自定义的 Event 类
private final Map<Object, List<Method>> subscriber;

/* 省略部分代码 */

@Override
public void run() {
    subscriber.forEach((sub, methods) -> methods.stream()
            // 筛选匹配事件方法
            .filter(m -> {
                // 即使通用类型不匹配,也会返回 true
                return m.getParameters()[0].getType().isAssignableFrom(event.getClass());
            })
            .forEach(m -> {
                try {
                    m.invoke(sub, event);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    LOGGER.error("...", e);
                }
            })
    );
}

注意:订阅者映射中给定的方法已经具有所需的返回类型、1 个参数和用于识别事件方法的注解。

编辑: 来自评论的信息:
问题在于,当我检查 Event<Integer> isAssignableFrom( Event<String> ) 时,Java 返回 true。

英文:

I'm currently building an event system to handle some events in my application. The EventDispatcher calls methods with parameters, which are assignable from the event's class. This works fine with non-parametrized parameters but i cant find a solution to do this with parametrized arguments (parameters with generic type).<br>
How can i filter for those too?

Here is a small excerpt from my Dispacher:

private final Event event; // custom Event-class
private final Map&lt;Object, List&lt;Method&gt;&gt; subscriber;

/* snip */

@Override
public void run() {
    subscriber.forEach((sub, methods) -&gt; methods.stream()
            // filter for matching event methods
            .filter(m -&gt; {
                // returns true, even if generic types do not match
                return m.getParameters()[0].getType().isAssignableFrom(event.getClass());
            })
            .forEach(m -&gt; {
                try {
                    m.invoke(sub, event);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    LOGGER.error(&quot;...&quot;, e);
                }
            })
    );
}

Note: the given methods in the subscriber map already have the required return type,1 parameter and the Annotation to identify event-methods.

EDIT: From the comments:
The problem is, that Java returns true, when I check for Event&lt;Integer&gt; isAssignableFrom( Event&lt;String&gt; )

答案1

得分: 0

经过一些测试和进一步阅读,我提出了一个测试来查看是否可以通过它们的类型来匹配泛型:

private static boolean test(Type type1, Type type2) {
    if (type1 == type2) return true;
    if (type1.getTypeName().equals(type2.getTypeName())) {
        if (type1 instanceof ParameterizedType || type2 instanceof ParameterizedType) {
            if (type1 instanceof ParameterizedType && type2 instanceof ParameterizedType) {
                Type[] type1Params = ((ParameterizedType) type1).getActualTypeArguments();
                Type[] type2Params = ((ParameterizedType) type2).getActualTypeArguments();
                if (type1Params.length != type2Params.length) return false;
                for (int i = 0; i < type1Params.length; i++) {
                    if (!test(type1Params[i], type2Params[i])) return false;
                }
                return true; // 所有泛型类型在两个类型中都是成对相等的
            }
            return false; // 一个带有泛型类型,另一个没有
        }
        return true; // 两者都没有泛型类型
    }
    return false; // 按名称不相等
}

我的结果:

  • 你可以使用这个方法来匹配方法的两个参数,因为一个Method可以通过getGenericParameterTypes返回一个Type[]。
  • 你不能检查两个实例是否具有相同的泛型类型。因为你只能通过getClass获取Type,只有从中获取实例的类的Type将被返回,不包括泛型类型。<br>
    参见类型擦除
英文:

After some testing and further reading i came up with a test to see if i can match the generics by their Types:

private static boolean test(Type type1, Type type2) {
    if (type1 == type2) return true;
    if (type1.getTypeName().equals(type2.getTypeName())) {
        if (type1 instanceof ParameterizedType || type2 instanceof ParameterizedType) {
            if (type1 instanceof ParameterizedType &amp;&amp; type2 instanceof ParameterizedType) {
                Type[] type1Params = ((ParameterizedType) type1).getActualTypeArguments();
                Type[] type2Params = ((ParameterizedType) type2).getActualTypeArguments();
                if (type1Params.length != type2Params.length) return false;
                for (int i = 0; i &lt; type1Params.length; i++) {
                    if (!test(type1Params[i], type2Params[i])) return false;
                }
                return true; // all generic types in both types are equal pairwise
            }
            return false; // one with generic type and one without
        }
        return true; // both no generic types
    }
    return false; // not equal by name
}

My results:

  • You can match two parameters of methods with this because a Method can return a Type[] with getGenericParameterTypes.
  • You cannot check if two instances have the same generic type. Because you get the Type via getClass only the Type of the Class you have the instance from will be returned without the Generic types.<br>
    See Type Erasure

huangapple
  • 本文由 发表于 2020年10月17日 01:32:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/64393829.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定