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

C# 如何将委托作为参数传递给订阅作为事件处理程序?,c#,events,delegates,C#,Events,Delegates,我有一个外部应用程序,它提供一个事件StkQuit 我在一个静态类中订阅此事件,该类处理我的应用程序和外部应用程序之间的所有通信。我想使用表单类上的另一个处理程序订阅StkQuit事件 此处理程序将通知用户外部应用程序已关闭。我希望在静态类中有一个名为SubscribeToStkQuit的泛型方法,该方法接受委托作为参数,并将该委托(指我表单类上的处理程序)订阅到StkQuit事件 这可能吗?这是实现此类功能的最优雅/最简单的方式吗 我的示例代码: 表单类 public delegate voi

我有一个外部应用程序,它提供一个事件
StkQuit

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

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

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

我的示例代码:

表单类

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 static AgUiApplication StkUiApplication
{
    get { return _stkUiApplication; }
}
private void SubscribeToStkQuit()
{
    UtilStk.StkUiApplication.OnQuit += StkQuit;
}

private void StkQuit()
{
    MessageBox("TEST");
}
静态类

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 static AgUiApplication StkUiApplication
{
    get { return _stkUiApplication; }
}
private void SubscribeToStkQuit()
{
    UtilStk.StkUiApplication.OnQuit += StkQuit;
}

private void StkQuit()
{
    MessageBox("TEST");
}
[更新]

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

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);
}
这个很好用。所以我想我应该为40; u stkuiaapplication)创建一个公共属性并以相同的方式从form类中订阅:

静态类

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 static AgUiApplication StkUiApplication
{
    get { return _stkUiApplication; }
}
private void SubscribeToStkQuit()
{
    UtilStk.StkUiApplication.OnQuit += StkQuit;
}

private void StkQuit()
{
    MessageBox("TEST");
}
表单类

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 static AgUiApplication StkUiApplication
{
    get { return _stkUiApplication; }
}
private void SubscribeToStkQuit()
{
    UtilStk.StkUiApplication.OnQuit += StkQuit;
}

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

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

这将导致内存泄漏

除此之外,代码的问题在于
ForceClose()
的签名与
\u stkuiaapplication不匹配。在退出时
必须是
ForceClose(对象发送方,某种目标方)

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

编辑:

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

private static AgUiApplication _stkUiApplication;
因此,它将在您的应用程序期间有效。将事件处理程序添加到

 _stkUiApplication.OnQuit
传递对窗体类实例上的方法的引用。此引用现在将在应用程序的生命周期内保留,因此不能对其进行垃圾收集

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

我错误地认为您一开始是在描述web表单,这稍微改变了一些事情(您可能只实例化了一个
表单
),但不管怎样,上面的内容都是正确的。这是一个很好的实践

要解决您当前的问题,请执行以下操作: 您需要键入传递给以下对象的参数:

public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
    _stkUiApplication.OnQuit += subscribeHandler;          
}
要成为
\u stkuiaapplication.OnQuit的类型

差不多

public static void SubscribeToStkQuit(EventHandler<EventArgs> subscribeHandler)
{
    _stkUiApplication.OnQuit += subscribeHandler;          
}
是的,你可以

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

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

public event EventHandler Quit { add { _stkUiApplication.OnQuit += value; } remove { _stkUiApplication.OnQuit -= value; } }
关于操作和函数,它们也是委托,因此您可以在任何地方使用它们作为任何委托的输入参数


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

这看起来非常优雅/简单…你不喜欢哪一部分?@Cpfohl-
\u stkuiaapplication.OnQuit+=subscribebhandler抛出“无法将类型“System.Delegate”隐式转换为“AGI.Ui.Application.IAgUiApplicationEvents\u OnQuitEventHandler”…”,因此我将委托转换为上述类型,并得到一个运行时异常“无法将类型为dForceClose的对象转换为类型AGI.Ui.Application.IAgUiApplicationEvents\u OnQuitEventHandler”。有什么想法吗?(对不起!我没有仔细看),但请看一下@CrapHands的答案。他发现了这个问题。所有.NET事件都必须具有“object sender,EventArgs e”签名。我只是重申一下,我认为你不应该像那样连接到事件,你会泄漏内存。最好的办法是将事件连接到Global.asax中的另一个静态事件,或者在某个地方运行一次代码。执行此操作:UtilStk.OnQuit+=(发送方,参数)=>SomeClassInMyApp.TheStaticMethodToHandleIt();是否适合在实例方法本身中取消订阅
-=
不是静态的。静态方法
SubscribeToStkQuit
用于分配作为实例方法的处理程序。你能不能再解释一下内存泄漏,这样我就能理解:D?出于某种原因,lambda表达式在将“objectsender,Eventargs args”传递到ForceClose时给我带来了问题。我的行是这样的:
UtilStk.SubscribeToStkQuit((sender,e)=>ForceClose(objectsender,EventArgs e))-我看不出我的和你的有什么区别?@WulfgarPro应该更明确一些。当我说类似的话时,我的意思是您需要找到事件args的实际类型。将鼠标悬停在VS中的_stkuiaapplication.OnQuit上,找出它的实际类型,并用它替换这里的类型。另外,UtilStk.SubscribeToStkQuit((发送方,参数)=>ForceClose(对象发送方,事件参数));应该是UtilStk.SubscribeToStkQuit((发送方,参数)=>ForceClose(发送方,参数));