【问题标题】:How do I retrieve the Subscriber List for an Event at runtime?如何在运行时检索事件的订阅者列表?
【发布时间】:2010-12-28 04:08:35
【问题描述】:

在使用Delegate时,我可以使用Delegate.GetInvocationList()方法在运行时检索delegate的调用列表。

有没有办法访问与事件关联的订阅者列表?我从这个example (SO#1237001) 运行代码,即时窗口允许我将 SecondChange 事件转换为 System.MultiCastDelegate,然后调用 GetInvocationList 方法。

但是,在我的场景中,我正在使用 System.Windows.Forms.DataGridView,并且我想在运行时检查 CellClick 事件的调用列表。但是,当我在 CellClick 上尝试任何类型的演员时,我收到以下错误:

事件 'System.Windows.Forms.DataGridView.CellClick' 只能出现在左侧 += 或 -=

我可以看到这些事件的声明存在明显差异。在时钟示例中,事件声明如下:

public event Func<DateTime, bool> SecondChange;

在 DataGridView 中,事件声明如下:

[SRDescription("DataGridView_CellClickDescr"), SRCategory("CatMouse")]
public event DataGridViewCellEventHandler CellClick
{
    add
    {
        base.Events.AddHandler(EVENT_DATAGRIDVIEWCELLCLICK, value);
    }
    remove
    {
        base.Events.RemoveHandler(EVENT_DATAGRIDVIEWCELLCLICK, value);
    }
}

为什么可以在 Clock 示例中调用 GetInvocationList,而不能在 DataGridView 事件中调用?有什么方法可以让我从 GetInvocationList 返回的 DataGridView 事件中获取相同类型的信息?

【问题讨论】:

    标签: c# winforms events


    【解决方案1】:

    event 的全部意义在于它定义(仅)add/remove API(就像属性如何定义 get/set)。

    事件的全部意义是在外部你不能这样做(访问订阅者)。我猜在“时钟”示例中,访问列表的代码是 inside 声明event 的类型;这很好:在类型内部,您可以完全访问支持的实现(通常是委托字段)。

    在外部,您应该只关心自己的处理程序,因为您订阅了它们,因此您已经知道这些处理程序。存在获取支持者的尝试,但它很脆弱,不推荐使用。在这种情况下,它使用EventHandlerList,例如。

    为什么需要这个?这通常意味着您做错了什么(对不起,但确实如此)。

    【讨论】:

    • 我见过的访问订阅者列表的最常见原因是执行全局取消订阅。这在某些情况下肯定很有用(特别是那些外部控制器想要“退出”一个对象但不能因为监听器仍然订阅的情况)。一个一致的removeAll 事件机制会很有用。
    • 好吧,它可以将对象释放到 void... 事件让订阅者保持活力,而不是相反。除非他们在其他地方有引用,否则没有多少订阅者会让对象保持活动状态。
    • 我只是想编写一个单元测试来确保我的对象已经订阅了 DataGridView 的事件。也许是我从错误的方向看问题,或者这个测试不值得写。
    • 也许做一些事情导致事件被触发?如有必要,使用反射调用受保护的OnCellClick 方法?
    • 另一种选择是使用反射得到Events,使用反射得到EVENT_DATAGRIDVIEWCELLCLICK,然后合并。不漂亮,而且脆弱(至少在理论上;它不太可能改变)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 2013-05-18
    • 2021-09-22
    相关资源
    最近更新 更多