Detach event handler after attaching method with passed parameter

久未见 提交于 2019-12-08 05:55:42

问题


I need to pass a parameter (in C#) to an event handler and then be able to detach the event handler.

I attach the event handler and pass the parameter:

_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);

The event is called as expected. I try to detach the event handler:

_map.MouseLeftButtonUp -= (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);

The code executes without error, but does not seem to detach.

If I attach the event handler the more conventional way (without passing a parameter):

_map.MouseLeftButtonUp+=_map_MouseLeftButtonUp;

and detach

_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp;

everything works as expected

Detaching the event handler (that takes a parameter) via the more conventional way

_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp2;

gives me an error saying the delegates don't match (which makes sense)

So my question is: Why is the event handler not really being detached when I pass a parameter, and is there a way to circumvent this problem.


回答1:


When you create a lambda (anonymous) function, you're actually creating a new function each time.

The reason your first two lines don't work is because they are two completely different functions that just happen to do the same thing. The correct way to detach would be to have subscribe and unsubscribe from a function, as you've already figured out.

An alternative, that's probably not worth it, is to save your lambda to a variable.

Action<object, MouseButtonEventArgs> myEventMethod = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
_map.MouseLeftButtonUp += myEventMethod;
// ...
_map.MouseLeftButtonUp -= myEventMethod;



回答2:


The reason is that two delegates are not equal:

  // You add one delegate instance 
  _map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);

  // ..And try to remove another one (not previous!) That's why the first delegate remains unremoved
  _map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);

You can convince youself by

  var x = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
  var y = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);

  if (Object.Equals(x, y)) { // <- You expected this behaviour
    ...
  }
  else { // <- Alas, this is a real situation: x != y
    ...
  }

The reason of such a behaviour is that when Object.Equals is not overridden (and in case of delegates it's not) Object.Equals works as Object.RefrenceEquals does, which checks instances referenses (addresses). Sure, that addresses of x and y are different as well as two your delegates



来源:https://stackoverflow.com/questions/17995339/detach-event-handler-after-attaching-method-with-passed-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!