【问题标题】:how to check if a method can be handler of an event through C# reflection? [duplicate]如何通过 C# 反射检查方法是否可以作为事件的处理程序? [复制]
【发布时间】:2013-06-02 16:12:47
【问题描述】:

我创建了一个基于事件的系统,其中一个类将提供一堆事件,另一个类及其成员方法可以作为其事件处理程序附加到第一个类,并且...我只想做这样的事情

if(isMethodCompatibleToEvent(...))
{
    connectMethodToEvent(...)
}

通过反射,连接是这样完成的:

void connectMethodToEvent(object methodTarget, MethodInfo mi,
    object eventTarget, EventInfo ei)
{
    Delegate handler = Delegate.CreateDelegate(ei.EventHandlerType, methodTarget, mi);
    ei.AddEventHandler(eventTarget, handler);
}

如果方法与事件不兼容,它会抛出异常,为了解决这个问题,我想在创建方法委托之前创建一些检查,但是如何?

bool isMethodCompatibleToEvent(object methodTarget, MethodInfo mi,
    object eventTarget, EventInfo ei)
{
    // HOW ?
}

【问题讨论】:

  • 如果您的异常来自分配handler 的行,请将CreateDelegate 的重载更改为包含throwOnBindFailure 为假。然后在继续之前检查handler 是否变为null。如果您的异常来自第二行,AddEventHandler 调用,则有些奇怪。请注意,handler 的类型应该与事件的类型完全匹配(不要尝试在事件的泛型中使用逆变)。

标签: c# events reflection methods delegates


【解决方案1】:
  • 形参个数必须相同。
  • 形式参数的“引用”必须相同。 (从技术上讲,带有out 参数的方法可以用于带有ref 参数的事件,反之亦然,但我不推荐它。)
  • 每种形式参数类型必须兼容。对于值类型,它们必须完全匹配。对于引用类型的形式参数,允许逆变。也就是说,如果您有一个要将 Giraffe 传递给委托的事件处理程序,则允许委托接受 Animal。
  • 返回类型的“voidness”必须相同; void 仅匹配 void
  • 对于非 void 返回类型,值类型必须完全匹配。对于返回引用类型的事件处理程序,允许协变。也就是说,如果事件处理程序说它返回 Animal 而委托返回 Giraffe,那很好。

这些不是所有规则,但足以应对绝大多数常见情况。

【讨论】:

  • (Technically a method with an out parameter may be used for an event with a ref parameter and vice versa but I don't recommend it.) 这是否意味着您可以不经反思就逃避明确的分配要求?
  • 试了一下,好像编译不允许它作为隐式转换。
  • @SLaks:因为从 CLR 的角度来看,“out”只不过是带有属性的“ref”,因此有许多偷偷摸摸的方法可以将带有“out”参数的方法与带有“参考”参数。我现在不记得它们是什么,但基本上有一些方法可以围绕编译器进行最终运行。围绕“out”的明确赋值规则仅仅是 C# 语言的约定;它们绝不是由运行时强制执行的。
  • 是的;我应该意识到这一点。我猜Delegate.CreateDelegate 的“反思性”足以违反 C# 的 language 规则(因为 CLR 较弱)。还有哪些其他方式?覆盖?其他语言?
  • @SLaks:覆盖:是的,我似乎记得有一些方法可以通过覆盖来混淆 refness/outness,但我不记得细节了。其他语言,绝对;你可以在 IL 中为所欲为。
【解决方案2】:

您需要比较方法和委托的签名(定义事件的类型):如果它们匹配,则可以将方法组合到事件中。

参数和返回类型的精确匹配显然是最简单的,但也要考虑隐式转换也可以应用(取决于您的要求,使用Type.IsAssignableFrom 可能就足够了)。

检查 C# 语言规范中有关方法和事件类型兼容性的规则将是第一步。

【讨论】:

    猜你喜欢
    • 2014-04-24
    • 1970-01-01
    • 2013-08-04
    • 2012-11-13
    • 2013-02-20
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多