Предотвращение одного назначения обработчика события несколько раз
Если я назначаю обработчик события во время выполнения, и он находится в месте, которое можно вызвать несколько раз, рекомендуется использовать несколько назначений одного и того же обработчика для одного и того же события.
object.Event += MyFunction
Добавление этого в пятно, которое будет вызываться более одного раза, будет выполнять обработчик "n" раз (разумеется).
Я попытался удалить любой предыдущий обработчик, прежде чем пытаться добавить через
object.Event -= MyFunction;
object.Event += MyFunction;
Это работает, но кажется каким-то образом. Любые предложения по правильному обращению;) этого сценария.
Ответы
Ответ 1
Багет прав насчет использования явно реализованного события (хотя там есть явная реализация интерфейса и полный синтаксис события). Вы, вероятно, можете уйти от этого:
private EventHandler foo;
public event EventHandler Foo
{
add
{
// First try to remove the handler, then re-add it
foo -= value;
foo += value;
}
remove
{
foo -= value;
}
}
Это может иметь некоторые случаи с нечетным краем, если вы когда-либо добавляете или удаляете многоадресные делегаты, но это маловероятно. Он также нуждается в тщательной документации, поскольку это не так, как обычно работают события.
Ответ 2
Я стараюсь добавить обработчик события в путь, который выполняется один раз, например, в конструкторе.
Ответ 3
Вы можете реализовать собственное хранилище делгатов и проверить уникальность при добавлении их в событие. См. Ниже пример EventOwner2. Я не знаю, как это делает производительность мудрым, но, опять же, это не всегда проблема.
using System;
using System.Collections.Generic;
namespace EventExperiment
{
class Program
{
static void Main(string[] args)
{
IEventOwner e=new EventOwner2();
Subscriber s=new Subscriber(e);
e.RaiseSome();
Console.ReadKey();
}
}
/// <summary>
/// A consumer class, subscribing twice to the event in it constructor.
/// </summary>
public class Subscriber
{
public Subscriber(IEventOwner eventOwner)
{
eventOwner.SomeEvent += eventOwner_SomeEvent;
eventOwner.SomeEvent += eventOwner_SomeEvent;
}
void eventOwner_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(DateTimeOffset.Now);
}
}
/// <summary>
/// This interface is not essensial to this point. it is just added for conveniance.
/// </summary>
public interface IEventOwner
{
event EventHandler<EventArgs> SomeEvent;
void RaiseSome();
}
/// <summary>
/// A traditional event. This is raised for each subscription.
/// </summary>
public class EventOwner1 : IEventOwner
{
public event EventHandler<EventArgs> SomeEvent = delegate { };
public void RaiseSome()
{
SomeEvent(this,new EventArgs());
}
}
/// <summary>
/// A custom event. This is raised only once for each subscriber.
/// </summary>
public class EventOwner2 : IEventOwner
{
private readonly List<EventHandler<EventArgs>> handlers=new List<EventHandler<EventArgs>>();
public event EventHandler<EventArgs> SomeEvent
{
add
{
lock (handlers)
if (handlers!=null&&!handlers.Contains(value))
{
handlers.Add(value);
}
}
remove
{
handlers.Remove(value);
}
}
public void RaiseSome()
{
EventArgs args=new EventArgs();
lock(handlers)
foreach (EventHandler<EventArgs> handler in handlers)
{
handler(this,args);
}
}
}
}
Ответ 4
Что такое модификатор доступа для объекта?
Если он является конфиденциальным, вам нужно только беспокоиться о том, что объект, содержащий объект, обработчик события.
Если он внутренне, вам нужно только беспокоиться о том, что содержащая сборка устанавливает обработчик события.
Если это общедоступно, тогда оно широко открыто.
Если "объект" можно сделать закрытым в содержащем классе, вы можете сделать свои проверки намного более эффективными, контролируя назначение обработчика событий в локальном классе.
Если требуется "внутреннее" или "общедоступное" и уникальность, перейдите к классу-оболочке, который скрывает "объект" и вместо этого предоставляет метод назначения обработчика события с вашими чеками, чтобы обеспечить уникальность.