正在注销事件处理程序
本文关键字:程序 事件处理 注销 | 更新日期: 2024-09-27 01:23:17
我有一个类,当收到一些消息时,它可以引发事件。此外,它还可以订阅来自同一类的其他实例的消息。(请参阅下面的缩短类。)我在注销事件处理程序时遇到问题。。。调试时,我可以看到Delegate.Remove被调用(在另一个语法版本中),但调用列表中没有删除任何内容。。。
class MyClass
{
private event EventHandler<EventArgs> MessageReceived;
public void SubscribeToMessages(Action<object, EventArgs> eventHandler)
{
this.MessageReceived += new EventHandler<EventArgs>(eventHandler);
}
public void UnsubscribeFromMessages(Action<object, EventArgs> eventHandler)
{
this.MessageReceived -= new EventHandler<EventArgs>(eventHandler);
}
private void MessageFromOtherObject_Received(object sender, EventArgs arg)
{
}
public void StartListeningToObject(MyClass obj)
{
obj.SubscribeToMessages(MessageFromOtherObject_Received);
}
public void StopListeningToObject(MyClass obj)
{
obj.UnsubscribeFromMessages(MessageFromOtherObject_Received);
}
}
void Test()
{
MyClass mainObj = new MyClass();
MyClass otherObj = new MyClss();
mainObj.StartListeningToObject(otherObj);
//...
mainObj.StopListeningToObject(otherObj);
}
因此,在调用StopListeningToObject()时,我可以看到它试图删除处理程序,但它仍然存在,并且事件仍然在mainObj上被触发。。。
现在根据我所知道的和我读到的
this.MessageReceived -= new EventHandler<EventArgs>(eventHandler);
语法应该可以正常工作,但它似乎认为这显然是一个不同的委托。
我做错了什么???
非常感谢您的建议!
您的代码被破坏的原因是您创建了以下两种方法:
public void SubscribeToMessages(Action<object, EventArgs> eventHandler)
{
this.MessageReceived += new EventHandler<EventArgs>(eventHandler);
}
public void UnsubscribeFromMessages(Action<object, EventArgs> eventHandler)
{
this.MessageReceived -= new EventHandler<EventArgs>(eventHandler);
}
而不是仅仅从事件中添加/删除处理程序(这是你应该做的),你实际上在做一些完全不同的事情。
SubscribeToMessages
正在添加一个事件处理程序,该事件处理程序在被调用时将调用eventHandler
委托的Invoke
方法。
当您调用UnsubscribeFromMessages
时,您正试图删除处理程序,该处理程序的主体是对已传递的eventHandler
实例的Invoke
方法的调用。但是,您将不同的Action
实例传递给这两个方法调用中的每一个(即使这两个不同的操作都指向同一个方法/对象对),因此您试图添加/删除的事件处理程序都指向不同的Action
实例,因此不被视为相等。
如果您只是直接向事件添加/删除处理程序,而不是添加第二层间接处理程序,即添加一个调用事件处理程序的事件处理程序,该事件处理程序调用实际方法,那么您就可以了。
或者,不要让您正在使用的订阅/取消订阅方法具有与您的事件不同的委托。让它们接受实际事件类型的委托,这样您就可以简单地添加/删除它们,这也将删除额外的间接层。
为什么如此复杂?为什么你需要私人活动?保持简单!
class Program
{
static void Main(string[] args)
{
}
void Test()
{
MyClass mainObj = new MyClass();
MyClass otherObj = new MyClass();
mainObj.StartListeningToObject(otherObj);
//...
mainObj.StopListeningToObject(otherObj);
}
}
class MyClass
{
public event EventHandler<EventArgs> MessageReceived;
private void MessageFromOtherObject_Received(object sender, EventArgs arg)
{
//do some work
}
public void StartListeningToObject(MyClass obj)
{
obj.MessageReceived += MessageFromOtherObject_Received;
}
public void StopListeningToObject(MyClass obj)
{
obj.MessageReceived -= MessageFromOtherObject_Received;
}
}
顺便说一句,别忘了触发那个事件!
问题是,注册的委托的目标实际上是eventHandler.Invoke
,而不是您想要委托的目标/方法。然后,当您尝试删除处理程序时,它是针对新委托对象的Invoke
方法的,因此它们不被视为相等,并且保留原始注册。您要委派给MessageFromOtherObject_Received
。有三种选择
- 直接在
Start
/StopListeningToObject
中进行添加/删除 - 将
UnsubscribeFrom
/SubscribeToMessages
的参数类型更改为EventHandler<EventArgs>
-
通过创建具有正确目标/方法的代表
var handler = (EventHandler<EventArgs>)Delegate.CreateDelegate(typeof(EventHandler<EventArgs>), eventHandler.Target, eventHandler.Method); this.MessageReceived += handler;
在CCD_ 17中使用类似的代码来移除处理程序。