Избегайте дублирования подписок на события в C # - PullRequest
19 голосов
/ 03 мая 2009

Как бы вы предложили лучший способ избежать дублирования подписок на события? если эта строка кода выполняется в двух местах, событие запускается дважды. Я пытаюсь избежать подписки на сторонние события дважды.

theOBject.TheEvent += RunMyCode;

В моем установщике делегатов я могу эффективно запустить это ...

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

но это лучший способ?

Ответы [ 5 ]

20 голосов
/ 03 мая 2009

Я думаю, самый эффективный способ - сделать ваше событие свойством и добавить к нему блокировки параллелизма, как в этом примере :

private EventHandler _theEvent;
private object _eventLock = new object();
public event EventHandler TheEvent
{
    add
    {
        lock (_eventLock) 
        { 
            _theEvent -= value; 
            _theEvent += value; 
        }
    }
    remove
    {
        lock (_eventLock) 
        { 
           _theEvent -= value; 
        }
    }
}
5 голосов
/ 03 мая 2009

Я делал это раньше .... предполагается, что приемлемо, что последний подписчик - это тот, кого вызывают.

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);
            }
        }
    }
}
2 голосов
/ 03 мая 2009

Ваш код многопоточный? Блокировка параллелизма необходима только тогда, когда она многопоточная. Если это не накладные расходы.

Таким образом, ваш подход отказа от подписки и подписки правильный.

Спасибо

1 голос
/ 03 мая 2009

Если у вас есть источник для класса theObject, у вас есть доступ к InvocationList из TheEvent. Вы можете реализовать собственный метод доступа для события и проверить его перед добавлением.

Однако я думаю, что ваш подход тоже подойдет.

0 голосов
/ 03 мая 2009

Я использую ваш подход, кроме одной детали. Я думаю, что события должны быть подписаны, когда вы создаете новый экземпляр подписчика или theObject, это делает код более прямым. Таким образом, все, что вам нужно, - это просто внимательно следить за правильной утилизацией предметов (для этого удобно утилизировать паттен).

Вы упомянули, что используете стороннее событие, это означает, что вы не можете предоставить собственную реализацию методов добавления / удаления, как вам было рекомендовано. Но в ваших собственных классах с вашими собственными событиями вы должны определить собственную реализацию методов добавления / удаления для события, чтобы решить вашу проблему.

...