2012-01-25 9 views
11

tengo el siguiente patrón de diseño:¿Cómo comprobar si ManualResetEvent se ha eliminado al intentar establecerlo() en un EventHandler?

var myObjectWithEvents = new ObjectWithEvents(); 
    using (var mre = new ManualResetEvent(false)) { 
     var onEvent = new EventHandler<EventArgs>((sender, e) => { mre.Set(); }); 
     try { 
      myObjectWithEvents.OnEvent += onEvent; 
      var task = Task.Factory.StartNew(() => { 
       myObjectWithEvents.DoSomethingThatShouldRaiseAnEvent(); 
      }); 
      var timedOut = !mre.WaitOne(10000); 
     } 
     finally { 
      myObjectWithEvents.OnEvent -= onEvent; 
     } 
    } 

Mi problema es que si OnEvent se eleva después de que los WaitOne tiempo de espera y pasos de ejecución de cada bloque using, el manejador onEvent evento local seguirá llamándose y tratar de configure el ManualResetEvent mre que ya habrá sido eliminado, aunque onEvent no debería estar registrado en OnEvent.

Una solución sencilla sería la de comprobar si mre ya se ha dispuesto, pero por desgracia no hay ningún campo, y creo envolver mre.Set() dentro de un bloque catch tratar de ignorar la excepción no está limpio dado que la excepción podría ocurrir muy frecuentemente.

¿Qué sugieres como la mejor y más simple forma de lograr el propósito del patrón de código anterior (es decir, esperar a que se genere un evento) sin toparse con este tipo de problema?

Editar: Gracias a sus respuestas, he creado la siguiente extensión y sustituido mre.Set() con mre.TrySet():

public static void TrySet(this ManualResetEvent mre) { 
     if (!mre.SafeWaitHandle.IsClosed) mre.Set(); 
    } 
+0

¿Podría dar más detalles sobre los requisitos de su aplicación? Usted pregunta por "la mejor y más simple forma de lograr el propósito del patrón de código anterior", pero eso nos deja adivinando en qué se basan sus requisitos con respecto a su código actual. – Justin

+0

¿Causa problemas al ejecutar Set() en MRE descartado? – sll

+0

Sí mre.Set() en mre dispuesto emitirá una excepción ... –

Respuesta

7

Usted puede tratar de comprobarlo directamente en el hotel mre.SafeWaitHandle.IsClosed

9
ManualResetEvent.SafeWaitHandle.IsClosed 

parece extraño, pero la única cosa que el disponer que hace es cerrar el safeHandler , que es el único objeto que está destinado a ...

El Eliminar del SafeWaitHandle, cambia esta propiedad de False a True.

+0

+1 desde que es el primero en sugerir la bandera 'IsClosed' – sll

+0

Gracias ssl! apreciado –

1

Como caso probar con el interruptor booleano simple que indica si el establecimiento ManualResetEvent es real:

bool isMreSync = true; 
var myObjectWithEvents = new ObjectWithEvents(); 
using (var mre = new ManualResetEvent(false)) 
{ 
    var onEvent = new EventHandler<EventArgs>((sender, e) => 
       { 
        if (isMreSync) 
        { 
         mre.Set(); 
        } 
       }); 

    // try ... finally block 
} 

isMreSync = false; 

Si el evento podría ser ejecutado de forma asíncrona: sincroniza el acceso al conmutador booleano.

Cuestiones relacionadas