2010-06-24 20 views
26

Como regla general, ¿hay alguna circunstancia en la que sea aceptable que un método responsable de escuchar un evento genere una excepción (o permita que lancen) que la clase que plantea el evento deba manejar?¿Los controladores de eventos en C# deberían generar alguna excepción?

Dado que tal excepción impediría que otros oyentes de ese evento sean llamados posteriormente, parece un poco "antisocial" permitir que esto suceda, pero por otro lado, si hay una excepción, ¿qué debería hacer? ?

+0

También están los CancelEventArgs. http://msdn.microsoft.com/en-us/library/system.componentmodel.canceleventargs.aspx – simendsjo

+0

No entiendo lo que quiere decir, aquí. ¿Quieres decir en el lado de recibir de decir Button1_Click, quieres lanzar una excepción? –

+0

@Rob: supongamos que tiene un proceso de ejecución larga con un evento finalizado. 10 métodos se registran con esto. Si uno de ellos lanza una excepción, no se llamará al resto. – simendsjo

Respuesta

18

Lanzar una excepción desde un controlador de eventos es en muchos aspectos similar a lanzar una excepción desde un método IDisposable.Dispose (o un destructor C++). Hacerlo crea estragos en la persona que llama porque los deja con poca opción.

  1. Ignore la excepción y deje que se propague. Esto rompe su contrato para informar a todos los oyentes de un evento. Este es un problema muy real si alguien encima de ellos en la pila detecta la excepción.
  2. Captúralo y llama a los otros controladores y vuelve a lanzar. ¿Pero qué sucede si uno de los otros tira también?
  3. Trague la excepción. Esto es simplemente malo en general. Las fuentes de eventos no deberían tener conocimiento de quién llama y, por lo tanto, no pueden saber qué están tragando.
  4. Bloquea el proceso porque estás en un brindis.

De todos estos # 4 es la mejor opción. Pero esto es rara vez hecho y no se puede contar con.

creo que en su componente que realmente sólo tiene unas pocas opciones

  • a la que llama el código que está lanzando y están en la mejor posición para manejar la excepción. Si no es manejable por usted, entonces no es razonable esperar que sea manejado por otra persona. Por lo tanto, rompa el proceso y termine con esto.
  • no llame a la API que arroja
+0

"Esto rompe su contrato para informar a todos los oyentes" - no están de acuerdo. No existe un contrato para informar a todos los oyentes si se produce una excepción. "Catch it call the other handlers and rethrow". - ¿cómo? Los eventos .NET no le proporcionan una lista de "otros controladores". "Bloquear el proceso ...": no bloquea el proceso, la excepción se propagará al código que generó el evento y se manejará como cualquier otra excepción. El proceso solo se bloqueará si no hay un controlador de nivel superior, de nuevo como cualquier otra excepción. – Joe

+5

@Joe el contrato para un evento es que todos los oyentes serán notificados. No notificarlos es una violación de ese contrato. ¿De qué sirve el evento 'Button.Click' si no puedo depender de que mi manejador realmente se ejecute cuando se hace clic en el botón? – JaredPar

+8

@Joe (cont) en este caso tener un controlador de nivel superior es lo peor que puede pasar. Lanzar un controlador de eventos es una violación del contrato de la gran mayoría de los eventos y causa suposiciones rotas en otros componentes. Esto conducirá con seguridad a futuros errores y/o excepciones en esos componentes. Estas fallas están lejos de la falla real original y, por lo tanto, son mucho más difíciles de rastrear. Falló rápido y falló ruidosamente. – JaredPar

1

En un mundo ideal, los controladores de eventos no deberían generar excepciones. La generación de una excepción en un controlador de eventos tiende a generar situaciones muy difíciles de manejar y comportamientos inesperados. Como mencionaste, esto bloquea a los controladores de eventos posteriores para que no vean el evento, y la excepción se propaga al código del productor del evento, ya que generó el evento.

Idealmente, los controladores de eventos deben ser rápidos (si son de larga duración, deben intentar programar el trabajo en una secuencia separada) y lo más cerca posible de errores.

+0

"Idealmente, los manejadores de eventos deben ser rápidos" - ¿qué pasa con Page.Load en una aplicación ASP.NET? No hay reglas generales aquí. La propagación de una excepción desde un controlador de eventos está perfectamente bien, y generalmente conduce a la situación fácil de manejar de una excepción que se propaga al manejador de nivel superior. – Joe

1

En una palabra ideales, no debería existir excepciones. En una palabra real del desarrollador, las excepciones siempre se esperan y deben ser interceptadas (atrapadas), propagadas o inhibidas según la situación lo requiera.

Así

son alguna vez cualquier circunstancia en la que que es aceptable para un método responsable de escuchar a un evento a lanzar una excepción

Sí. Puede esperar una excepción de cada método, responsable o no de un evento.

Para la captura de casi todos los excepción de un uso de aplicaciones de Windows:
AppDomain.CurrentDomain.UnhandledException
Application.ThreadException

5

Los únicos dos tipos de excepciones que procedan de eventos son los graves, potencialmente proceso termina como System.OutOfMemoryException o System.DllNotFoundException, y cosas que son claramente errores de programación, como System.StackOverflowException o System.InvalidCastException. Atrapar y eliminar este tipo de excepciones nunca es una buena idea: déjelos flotar hasta la cima y deje que el desarrollador decida qué hacer con ellos en un nivel de aplicación.

En cuanto al resto ... cualquier excepción común o jardín de excepción como System.IO.IOException se debe manejar dentro de su evento, y debe tener algún mecanismo para devolver esas condiciones de error a la persona que llama.

+0

Oo, eso me hizo pensar ... ¿qué hay de 'ThreadAbortException'? – Flynn1179

+0

'ThreadAbortException' es interesante porque no importa si lo capturas o no, se volverá a lanzar al final de un bloque catch. –

+0

-1: Las excepciones solo deben manejarse dentro del evento (o en otro lugar) si sabes qué hacer con ellas. Y en el caso general (por ejemplo, dentro de un controlador para uno de los eventos en el Framework - Page.Load, Button.Click, etc.) no hay ningún mecanismo para devolver las condiciones de error a la persona que llama. – Joe

1

Algunas de las respuestas aquí sugieren que es malo tirar desde un controlador de eventos ("crea estragos para quien llama", "tiende a provocar situaciones muy difíciles de manejar y comportamientos inesperados", ...).

En mi humilde opinión esto no tiene sentido.

En el caso general, está perfectamente bien lanzar desde un controlador de eventos. No se ejecutarán otros manejadores de eventos, por supuesto, ni el controlador de eventos que arroja la ejecución hasta el final, ni ningún otro código entre el disparo del evento y el punto donde se detecta. ¿Y qué? Es perfectamente normal que el código no se ejecute cuando se lanza una excepción: si necesita garantizar que se ejecuta, entonces use un bloque finally.

Por supuesto, en cualquier caso específico es posible que desee considerar las excepciones, si las hay, que es apropiado manejar, al igual que con cualquier otro código.

Como siempre, no existen reglas estrictas que se apliquen en todas las circunstancias. Una de las respuestas aquí dice "los controladores de eventos deben ser rápidos ... y cerca de la ausencia de errores ...". Un contraejemplo es el evento ASP.NET Page.Load.

Una regla general en .NET es que casi siempre es una mala idea tragarse todas las excepciones: esto se aplica a los manejadores de eventos al igual que a cualquier otro código.

Así que la respuesta a la pregunta original "hay nunca ninguna circunstancia en la que es aceptable para un método responsable de escuchar a un evento para lanzar una excepción" es muy definitivamente .

Al igual que la respuesta a la pregunta "¿hay alguna circunstancia en la que sea aceptable que un método responsable de escuchar un evento trague excepciones" también es afirmativa.

+0

Creo que llamarlo "sin sentido" es un poco injusto, sin duda para los eventos manejados internamente. Probablemente consideraría lanzar una excepción si es necesario, pero si estoy escribiendo un controlador para un método en el código de otra persona, no tendría pensó que era apropiado lanzar (o incluso permitir) excepciones. – Flynn1179

+0

Lo que llamo 'sin sentido' son las declaraciones "crea estragos ...", "muy difícil de manejar ...", "comportamiento inesperado" que en mi humilde opinión solo es FUD. No estoy diciendo que sea absurdo atrapar o evitar arrojar excepciones en un controlador de eventos en algún caso específico. Sin duda, debe considerar lo que sucederá cuando se genere una excepción desde un controlador de eventos al diseñar su aplicación. – Joe

+0

Si algo irrecuperable ha sucedido, entonces tiene sentido que el manejador de eventos arroje una excepción (o permita que uno progrese de una llamada descendente). Simplemente debe entenderse que la clase que llama al manejador a través del evento permitirá (o al menos debería) que la excepción se propague y finalmente elimine todo el proceso o AppDomain, ya que no tiene suficiente contexto para saber cómo manejar la excepción . No se deben llamar a los otros manejadores, ya que el estado AppDomain puede dejar de ser válido, por lo que la cuestión de si se está rompiendo un contrato es discutible. –

Cuestiones relacionadas