注销事件处理程序

unregistering event handler

我有一个 class 可以在收到某些消息时引发事件。此外,它还可以订阅来自同一 class 的其他实例的消息。 (请参阅下面缩短的 class。)我在注销事件处理程序时遇到问题... 调试时我可以看到 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);
}

所以在调用 StopListentingToObject() 时我可以看到它试图删除处理程序,但它仍然存在,并且事件仍在 mainObj 上触发...

现在根据我所知道的和我读到的

this.MessageReceived -= new EventHandler<EventArgs>(eventHandler);

语法应该工作得很好,但它似乎认为这显然是一个不同的委托。

我做错了什么???

非常感谢您的任何建议!

为什么这么复杂?为什么需要私人活动?保持简单!

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

顺便说一句,别忘了触发那个事件!

你的代码被破坏的原因是因为你创建了这两个方法:

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

而不仅仅是来自事件的 adding/removing 处理程序(这是你应该做的)你实际上在做一些完全不同的事情。

SubscribeToMessages 正在添加一个事件处理程序,该事件处理程序在调用时将调用 eventHandler 委托的 Invoke 方法。

当您调用 UnsubscribeFromMessages 时,您试图删除处理程序,该处理程序的主体是对您已传递的 eventHandler 实例的 Invoke 方法的调用。但是,您将不同的 Action 实例传递给这两个方法调用中的每一个(即使这两个不同的操作都指向相同的 method/object 对),因此您尝试的事件处理程序add/remove 分别指代不同的 Action 个实例,因此不被视为相等。

如果您直接 add/remove 事件处理程序,而不是在第二层间接层中添加一个事件处理程序,该事件处理程序调用一个事件处理程序,该事件处理程序调用实际方法,您会没事的。

或者,您使用的 subscribe/unsubscribe 方法没有与事件不同的委托。让他们接受实际事件类型的代表,这样您就可以简单地 add/remove 他们,这也将删除额外的间接层。

问题在于,已注册的委托人的目标实际上是 eventHandler.Invoke,而实际上并不是您要委托给的 target/method。然后,当您尝试删除处理程序时,它是针对新委托对象的 Invoke 方法的,因此它们不被视为不相等,并且原始注册仍然存在。你想委派给 MessageFromOtherObject_Received。共有三个选项

  • 直接在Start/StopListeningToObject
  • 中做add/remove
  • UnsubscribeFrom/SubscribeToMessages的参数类型改为EventHandler<EventArgs>
  • 通过

    创建一个具有正确target/method的委托
    var handler = (EventHandler<EventArgs>)Delegate.CreateDelegate(typeof(EventHandler<EventArgs>), eventHandler.Target, eventHandler.Method);
    this.MessageReceived += handler;
    

    使用 UnsubscribeFromMessages 中的类似代码删除处理程序。