首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将委托作为参数传递给订阅作为事件处理程序?

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

Stack Overflow用户
提问于 2011-01-27 13:26:49
回答 2查看 6K关注 0票数 4

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

我在一个静态类中订阅此事件,它处理应用程序和外部应用程序之间的所有通信。我希望使用位于窗体类上的另一个处理程序订阅StkQuit事件。

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

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

我的示例代码:

表单类

代码语言:javascript
复制
public delegate void dForceClose();
public void SubscribeToStkQuit(dForceClose forceClose)
{
    UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose));
}
private void ForceClose()
{
    MessageBox.Show("TEST");
}

静态类

代码语言:javascript
复制
private static AgUiApplication _stkUiApplication;
public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
    _stkUiApplication.OnQuit += subscribeHandler;          
}

更新

根据注释,我更新了代码如下:

代码语言:javascript
复制
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触发时提供了一个处理程序:

代码语言:javascript
复制
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创建一个公共属性,并以同样的方式从form类订阅:

静态类

代码语言:javascript
复制
public static AgUiApplication StkUiApplication
{
    get { return _stkUiApplication; }
}

表单类

代码语言:javascript
复制
private void SubscribeToStkQuit()
{
    UtilStk.StkUiApplication.OnQuit += StkQuit;
}

private void StkQuit()
{
    MessageBox("TEST");
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-01-27 13:35:51

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

这会导致内存泄漏。

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

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

编辑:

对外部应用程序的引用是静态的:

代码语言:javascript
复制
private static AgUiApplication _stkUiApplication;

因此,它将在您的应用程序的持续时间内存活。将事件处理程序添加到

代码语言:javascript
复制
 _stkUiApplication.OnQuit

在窗体类的实例上传递对方法的引用。这个引用现在将保存在应用程序的生命周期中,因此它不能被垃圾收集。

要处理这种情况,可以在释放侦听对象时显式地取消注册(-=)处理程序,或者使用静态处理程序处理静态事件。

我错误地认为您最初描述的是web表单,这会稍微改变一些事情(您可能只会实例化一个Form),但不管怎么说,上述都是正确的。这是很好的实践。

要解决当前问题:您需要键入传递给:

代码语言:javascript
复制
public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
    _stkUiApplication.OnQuit += subscribeHandler;          
}

成为_stkUiApplication.OnQuit的类型

有点像

代码语言:javascript
复制
public static void SubscribeToStkQuit(EventHandler<EventArgs> subscribeHandler)
{
    _stkUiApplication.OnQuit += subscribeHandler;          
}

然后你就可以这样做:

代码语言:javascript
复制
public void SubscribeToStkQuit()
{
    UtilStk.SubscribeToStkQuit((sender, args) => ForceClose(sender, args));
}
票数 4
EN

Stack Overflow用户

发布于 2011-01-27 13:38:20

可以,停那儿吧!

但是最好使用动作和函数,它们在参数化方面是灵活的(它们都在系统名称空间中)。

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

代码语言:javascript
复制
public event EventHandler Quit { add { _stkUiApplication.OnQuit += value; } remove { _stkUiApplication.OnQuit -= value; } }

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

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4816892

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档