views:

753

answers:

5

How would you suggest the best way of avoiding duplicate event subscriptions? if this line of code executes in two places, the event will get ran twice. I'm trying to avoid 3rd party events from subscribing twice.

theOBject.TheEvent += RunMyCode;

In my delegate setter, I can effectively run this ...

theOBject.TheEvent -= RunMyCode;
theOBject.TheEvent += RunMyCode;

but is that the best way?

+5  A: 

I think, the most efficient way, is to make your event a property and add concurrency locks to it as in this Example:

private EventHandler _theEvent;
private object _eventLock = new object();
public event EventHandler TheEvent
{
    add
    {
        lock (_eventLock) 
        { 
            _theEvent -= value; 
            _theEvent += value; 
        }
    }
    remove
    {
        lock (_eventLock) 
        { 
           _theEvent -= value; 
        }
    }
}
Jose Basilio
copied and pasted from http://blog.davemorton.net/2009/02/preventing-duplicate-subscriptions-to.html
+2  A: 

see this article

Adinochestva
this is a great article, but I "checked" @Jose as the answer, since his code is inline, and is the same answer as the click through article.
ScottCate
+1  A: 

Is your code multi threaded ? Concurrency lock is needed only when its multi threaded. If not its a overhead.

As such your approach of unsubscribing and subscribing is correct.

Thanks

A: 

I use your approach except one detail. I think, that events should be subscribed when you create new instance of subscriber or theObject, this makes code more straight. Thus, all you need is just carefully watch after correct objects disposing (dispose patten is convenient solution for this).

You mentioned that you use 3rd party event, that means that you can't provide your own realisation for add/remove methods, as you have been advised. But in your own classes with your own events you should define your own realisation of add/remove methods for event in order to solve your problem.

Dmitry Lobanov
+1  A: 

I have done this before....it assumes it is acceptable that the last subscriber is what gets called.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            MyObject my = new MyObject();
            my.Changed += new EventHandler(my_Changed);
            my.Changed += new EventHandler(my_Changed1);

            my.Update();
            Console.ReadLine();
        }

        static void my_Changed(object sender, EventArgs e)
        {
            Console.WriteLine("Hello");
        }
        static void my_Changed1(object sender, EventArgs e)
        {
            Console.WriteLine("Hello1");
        }
    }
    public class MyObject
    {
        public MyObject()
        {
        }
        private EventHandler ChangedEventHandler;
        public event EventHandler Changed
        {
            add
            {
                ChangedEventHandler = value;
            }
            remove
            {
                ChangedEventHandler -= value;
            }
        }
        public void Update()
        {
            OnChanged();
        }

        private void OnChanged()
        {
            if (ChangedEventHandler != null)
            {
                ChangedEventHandler(this, null);
            }
        }
    }
}
joeln
nice, for those speed readers who may have missed it, this is the important line. ChangedEventHandler = value;instead of +=.Good for single use only -- might works for me in some cases -- thank you!
ScottCate