繁体   English   中英

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

[英]How to pass a delegate as an argument to subscribe as an event handler?

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

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

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

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

我的示例代码:

表格类

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

我仍然得到演员异常。 有任何想法吗 ??

[更新#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()不匹配_stkUiApplication.OnQuit它需要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<EventArgs> 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方式执行,不是吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM