C# pattern to prevent an event handler hooked twic

2020-01-25 03:07发布

Duplicate of: How to ensure an event is only subscribed to once and Has an event handler already been added?

I have a singleton that provides some service and my classes hook into some events on it, sometimes a class is hooking twice to the event and then gets called twice. I'm looking for a classical way to prevent this from happening. somehow I need to check if I've already hooked to this event...

9条回答
甜甜的少女心
2楼-- · 2020-01-25 03:46

You really should handle this at the sink level and not the source level. That is, don't prescribe event handler logic at the event source - leave that to the handlers (the sinks) themselves.

As the developer of a service, who are you to say that sinks can only register once? What if they want to register twice for some reason? And if you are trying to correct bugs in the sinks by modifying the source, it's again a good reason for correcting these issues at the sink-level.

I'm sure you have your reasons; an event source for which duplicate sinks are illegal is not unfathomable. But perhaps you should consider an alternate architecture that leaves the semantics of an event intact.

查看更多
祖国的老花朵
3楼-- · 2020-01-25 03:48

Microsoft's Reactive Extensions (Rx) framework can also be used to do "subscribe only once".

Given a mouse event foo.Clicked, here's how to subscribe and receive only a single invocation:

Observable.FromEvent<MouseEventArgs>(foo, nameof(foo.Clicked))
    .Take(1)
    .Subscribe(MyHandler);

...

private void MyHandler(IEvent<MouseEventArgs> eventInfo)
{
   // This will be called just once!
   var sender = eventInfo.Sender;
   var args = eventInfo.EventArgs;
}

In addition to providing "subscribe once" functionality, the RX approach offers the ability to compose events together or filter events. It's quite nifty.

查看更多
爷的心禁止访问
4楼-- · 2020-01-25 03:49

Create an Action instead of an event. Your class may look like:

public class MyClass
{
                // sender   arguments       <-----     Use this action instead of an event
     public Action<object, EventArgs> OnSomeEventOccured;

     public void SomeMethod()
     {
          if(OnSomeEventOccured!=null)
              OnSomeEventOccured(this, null);
     }

}
查看更多
叛逆
5楼-- · 2020-01-25 03:50

In silverlight you need to say e.Handled = true; in the event code.

void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    e.Handled = true; //this fixes the double event fire problem.
    string name = (e.OriginalSource as Image).Tag.ToString();
    DoSomething(name);
}

Please tick me if this helps.

查看更多
淡お忘
6楼-- · 2020-01-25 03:52

Explicitly implement the event and check the invocation list. You'll also need to check for null:

using System.Linq; // Required for the .Contains call below:

...

private EventHandler foo;
public event EventHandler Foo
{
    add
    {
        if (foo == null || !foo.GetInvocationList().Contains(value))
        {
            foo += value;
        }
    }
    remove
    {
        foo -= value;
    }
}

Using the code above, if a caller subscribes to the event multiple times, it will simply be ignored.

查看更多
冷血范
7楼-- · 2020-01-25 03:53

have your singleton object check it's list of who it notifies and only call once if duplicated. Alternatively if possible reject event attachment request.

查看更多
登录 后发表回答