sustentables sostenibles sostenible eventos evento español ejemplos caracteristicas c# events event-handling subscription

c# - sostenibles - Cómo garantizar que un evento solo esté suscrito a una vez



iso 20121 pdf (6)

Como otros han demostrado, puede anular las propiedades de agregar / eliminar del evento. Alternativamente, puede deshacerse del evento y simplemente hacer que la clase tome un delegado como argumento en su constructor (u otro método), y en lugar de activar el evento, llame al delegado proporcionado.

Los eventos implican que cualquiera puede suscribirse a ellos, mientras que un delegado es un método que puede pasar a la clase. Probablemente sea menos sorprendente para el usuario de su biblioteca, si solo usa eventos cuando realmente usa la semántica de uno a muchos que generalmente ofrece.

Me gustaría asegurarme de que solo me suscribo una vez en una clase en particular para un evento en una instancia.

Por ejemplo, me gustaría poder hacer lo siguiente:

if (*not already subscribed*) { member.Event += new MemeberClass.Delegate(handler); }

¿Cómo podría implementar este tipo de guardia?


Debería almacenar un indicador por separado que indique si se suscribió o, si tiene control sobre MemberClass, proporcionar implementaciones de los métodos para agregar y eliminar para el evento:

class MemberClass { private EventHandler _event; public event EventHandler Event { add { if( /* handler not already added */ ) { _event+= value; } } remove { _event-= value; } } }

Para decidir si se ha agregado o no el controlador, deberá comparar los Delegados devueltos de GetInvocationList () tanto en _event como en value.


Estoy agregando esto en todas las preguntas duplicadas, solo para el registro. Este patrón funcionó para mí:

myClass.MyEvent -= MyHandler; myClass.MyEvent += MyHandler;

Tenga en cuenta que al hacer esto cada vez que registre su controlador, se asegurará de que su controlador esté registrado solo una vez.


Me parece que una forma fácil de hacerlo es cancelar la suscripción a su controlador (que no se podrá suscribir si no se suscribe) y luego suscribirse.

member.Event -= eventHandler; member.Event += eventHandler;

Coloca la carga en el desarrollador, que es la forma incorrecta de hacerlo, pero para rápido y sucio, esto es rápido y sucio.


Si está hablando de un evento en una clase para el que tiene acceso a la fuente, puede colocar la guardia en la definición del evento.

private bool _eventHasSubscribers = false; private EventHandler<MyDelegateType> _myEvent; public event EventHandler<MyDelegateType> MyEvent { add { if (_myEvent == null) { _myEvent += value; } } remove { _myEvent -= value; } }

Eso garantizaría que solo un suscriptor pueda suscribirse al evento en esta instancia de la clase que proporciona el evento.

EDITAR por favor vea los comentarios sobre por qué el código anterior es una mala idea y no es seguro.

Si su problema es que una sola instancia del cliente se suscribe más de una vez (y necesita varios suscriptores), entonces el código del cliente deberá manejar eso. Entonces reemplace

no suscrito

con un miembro bool de la clase de cliente que se establece cuando se suscribe para el evento la primera vez.

Editar (después de aceptado): Basado en el comentario de @Glen T (el remitente de la pregunta) el código de la solución aceptada con la que se dirigió es en la clase de cliente:

if (alreadySubscribedFlag) { member.Event += new MemeberClass.Delegate(handler); }

Donde alreadySubscribedFlag es una variable miembro en la clase de cliente que rastrea la primera suscripción al evento específico. Las personas que estén viendo el primer fragmento de código aquí, tengan en cuenta el comentario de @Rune: no es una buena idea cambiar el comportamiento de la suscripción a un evento de una manera no obvia.

EDITAR 31/7/2009: Consulte los comentarios de @Sam Saffron. Como ya dije y Sam está de acuerdo, el primer método presentado aquí no es una forma sensata de modificar el comportamiento de la suscripción al evento. Los consumidores de la clase necesitan saber sobre su implementación interna para comprender su comportamiento. No muy bueno.
@Sam Saffron también comenta sobre la seguridad del hilo. Supongo que se está refiriendo a la posible condición de carrera en la que dos suscriptores (cerca de) intentan suscribirse simultáneamente y ambos pueden terminar suscribiéndose. Un bloqueo podría usarse para mejorar esto. Si planea cambiar la forma en que funciona la suscripción a eventos, le aconsejo que lea acerca de cómo hacer que la suscripción agregue / elimine las cadenas de propiedades de manera segura .


U puede usar Postsharper para escribir un atributo solo una vez y usarlo en Eventos normales. Reutiliza el código. La muestra de código se proporciona a continuación.

[Serializable] public class PreventEventHookedTwiceAttribute: EventInterceptionAspect { private readonly object _lockObject = new object(); readonly List<Delegate> _delegates = new List<Delegate>(); public override void OnAddHandler(EventInterceptionArgs args) { lock(_lockObject) { if(!_delegates.Contains(args.Handler)) { _delegates.Add(args.Handler); args.ProceedAddHandler(); } } } public override void OnRemoveHandler(EventInterceptionArgs args) { lock(_lockObject) { if(_delegates.Contains(args.Handler)) { _delegates.Remove(args.Handler); args.ProceedRemoveHandler(); } } } }

Solo úsalo así.

[PreventEventHookedTwice] public static event Action<string> GoodEvent;

Para obtener más detalles, consulte Implementar Postsharp EventInterceptionAspect para evitar que un evento Handler se enganche dos veces.