如何将委托作为参数传递给订阅作为事件处理程序?

我有一个提供事件StkQuit的外部应用程序。

我在静态类中订阅此事件,该类处理我的应用程序和[外部]应用程序之间的所有通信。 我想使用另一个位于我的表单类的处理程序订阅StkQuit事件。

此处理程序将通知用户外部应用程序已关闭。 我想在名为SubscribeToStkQuit的静态类中有一个generics方法,它接受委托作为参数,并将该委托(指我的表单类的处理程序) StkQuitStkQuit事件。

这可能吗? 这是实现此类function的最优雅/最简单的方法吗?

我的示例代码:

表格类

 public delegate void dForceClose(); public void SubscribeToStkQuit(dForceClose forceClose) { UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose)); } private void ForceClose() { MessageBox.Show("TEST"); } 

静态类

 private static AgUiApplication _stkUiApplication; public static void SubscribeToStkQuit(Delegate subscribeHandler) { _stkUiApplication.OnQuit += subscribeHandler; } 

[更新]

根据评论,我已更新代码,如下所示:

 public delegate void dForceClose(object sender, EventArgs e); public void SubscribeToStkQuit(dForceClose forceClose) { UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose)); } private void ForceClose(object sender, Eventargs e) { MessageBox.Show("TEST"); } 

我仍然得到演员表exception。 有任何想法吗 ??

[更新#2]

我仍然遇到这个问题。 在我的静态类中,当OnQuit触发时,我已经有了一个处理程序:

 private static AgUiApplication _stkUiApplication; public static bool CheckThatStkIsAvailable() { object stkApplication = null; try { stkApplication = Marshal.GetActiveObject(_stkProgId); _stkUiApplication = stkApplication as AgUiApplication; _stkUiApplication.OnQuit += StkQuit; return true; } catch (Exception) { // handle this } } private static void StkQuit() { _stkUiApplication.OnQuit -= StkQuit; Marshal.FinalReleaseComObject(_stkUiApplication); Marshal.FinalReleaseComObject(_stkRoot); } 

这很好用。 所以我想我会为_stkUiApplication创建一个公共属性,并以相同的方式从表单类订阅:

静态类

 public static AgUiApplication StkUiApplication { get { return _stkUiApplication; } } 

表格类

 private void SubscribeToStkQuit() { UtilStk.StkUiApplication.OnQuit += StkQuit; } private void StkQuit() { MessageBox("TEST"); } 

如果使用实例方法订阅静态事件,则在处理静态事件之前不会对实例进行垃圾回收(除非您取消订阅)。

这将导致内存泄漏。

除此之外,你的代码的问题是ForceClose()的签名与ForceClose()不匹配它需要是ForceClose(object sender, SomeKindOfEventArgs e)

它应该是UtilStk.SubscribeToStkQuit(forceClose => (s, e){ForceClose();});

编辑:

您对外部应用的引用是静态的:

 private static AgUiApplication _stkUiApplication; 

所以它会在你的申请期间存在。 添加事件处理程序

  _stkUiApplication.OnQuit 

将引用传递给表单类实例上的方法。 此引用现在将在您的应用程序的生命周期中保留,因此不能进行垃圾回收。

要处理这种情况,要么在处理侦听对象时显式取消注册( – =)处理程序,要么使用静态处理程序处理静态事件。

我错误地认为你最初是在描述网络表单,这会改变一些事情(你可能只会实例化一个Form ),但无论如何,上述情况都适用。 这是一个很好的做法。

要解决当前问题:您需要输入传递给的参数:

 public static void SubscribeToStkQuit(Delegate subscribeHandler) { _stkUiApplication.OnQuit += subscribeHandler; } 

_stkUiApplication.OnQuit的类型

就像是

 public static void SubscribeToStkQuit(EventHandler subscribeHandler) { _stkUiApplication.OnQuit += subscribeHandler; } 

然后你可以这样做:

 public void SubscribeToStkQuit() { UtilStk.SubscribeToStkQuit((sender, args) => ForceClose(sender, args)); } 

是的你可以!

但最好使用在参数化方面灵活的动作和函数(所有这些都在System命名空间中)。

无论如何,我还有另一个建议:你为什么不使用事件访问器? 您可以在静态类中创建一个:

 public event EventHandler Quit { add { _stkUiApplication.OnQuit += value; } remove { _stkUiApplication.OnQuit -= value; } } 

关于操作和函数,这些也是委托,因此您可以在任何地方使用它们作为任何委托的输入参数。

也许您可以使用事件访问器并以.NET方式执行,不是吗?