utilizar una try tipos sharp que propiedades programacion para manejar las existen excepción excepciones errores ejemplos como catch capturar c# design-patterns exception events

una - throw exception c#



Usar eventos en lugar de excepciones para implementar el manejo de errores (9)

Estoy trabajando en un código que usa un patrón en sus negocios y niveles de datos que usa eventos para señalar errores, por ejemplo

resource = AllocateLotsOfMemory(); if (SomeCondition()) { OnOddError(new OddErrorEventArgs(resource.StatusProperty)); resource.FreeLotsOfMemory(); return; }

Esto parecía superficialmente bastante extraño, especialmente porque el código que lo llama necesita engancharse a los eventos (¡hay cuatro o cinco diferentes!).

El desarrollador me dice que de esta manera pueden referirse a las propiedades del recurso asignado en el código de manejo de errores, y esa responsabilidad de limpieza después de que este nivel conserve el error.

Lo cual tiene algún tipo de sentido.

La alternativa podría ser algo así como

resource = AllocateLotsOfMemory(); if (SomeCondition()) { BigObject temporary = resource.StatusProperty; resource.FreeLotsOfMemory(); throw new OddException(temporary); }

Mis preguntas son:

  1. Como este " BigObject " se libera cuando se lanza el objeto de excepción, ¿necesitamos este patrón?

  2. ¿Alguien más ha experimentado este patrón? Si es así, ¿qué escollos encontraste? ¿Qué ventajas hay?

¡Gracias!


1) es necesario? ningún patrón es absolutamente necesario

2) Windows Workflow Foundation hace esto con todos los resultados de las instancias de flujo de trabajo que se ejecutan dentro del tiempo de ejecución alojado. Solo recuerda que pueden ocurrir excepciones cuando intentas plantear ese evento, y es posible que desees hacer tu código de limpieza en un bloque Dispose o finally, dependiendo de la situación para garantizar que se ejecute.


A mí también me parece extraño. Hay algunas ventajas, como permitir múltiples "manejadores" pero la semántica es significativamente diferente al manejo normal de errores. En particular, me preocupa el hecho de que no se propague automáticamente en la pila, a menos que los manejadores de error emitan una excepción, la lógica seguirá funcionando como si todo estuviera bien cuando probablemente debería abortar la operación actual. .

Otra forma de pensar sobre esto: supongamos que el método está destinado a devolver un valor, pero ha detectado un error temprano. ¿Qué valor devuelves? Las excepciones comunican el hecho de que no hay un valor apropiado para devolver ...


Echa un vistazo a esta publicación de Udi Dahan. Es un enfoque elegante para despachar eventos de dominio. El póster anterior es correcto al decir que no se debe usar un mecanismo de evento para recuperarse de errores fatales, pero es un patrón muy útil para la notificación en sistemas débilmente acoplados:

public class DomainEventStorage<ActionType> { public List<ActionType> Actions { get { var k = string.Format("Domain.Event.DomainEvent.{0}.{1}", GetType().Name, GetType().GetGenericArguments()[0]); if (Local.Data[k] == null) Local.Data[k] = new List<ActionType>(); return (List<ActionType>) Local.Data[k]; } } public IDisposable Register(ActionType callback) { Actions.Add(callback); return new DomainEventRegistrationRemover(() => Actions.Remove(callback) ); } } public class DomainEvent<T1> : IDomainEvent where T1 : class { private readonly DomainEventStorage<Action<T1>> _impl = new DomainEventStorage<Action<T1>>(); internal List<Action<T1>> Actions { get { return _impl.Actions; } } public IDisposable Register(Action<T1> callback) { return _impl.Register(callback); } public void Raise(T1 args) { foreach (var action in Actions) { action.Invoke(args); } } }

Y para consumir:

var fail = false; using(var ev = DomainErrors.SomethingHappened.Register(c => fail = true) { //Do something with your domain here }


Esto me parece realmente extraño, en primer lugar IDisposable es tu amigo, úsalo.

Si se trata de errores y situaciones excepcionales, debe utilizar excepciones, no eventos, ya que es mucho más fácil de comprender, depurar y codificar.

Entonces debería ser

using(var resource = AllocateLotsOfMemory()) { if(something_bad_happened) { throw new SomeThingBadException(); } }


Otro problema importante con este enfoque son las preocupaciones de concurrencia.

Con el manejo tradicional de errores, los bloqueos se liberarán a medida que el control se mueva hacia arriba de la pila de llamadas al controlador de errores de forma controlada. En este esquema, todos los bloqueos se mantendrán cuando se invoque el evento. Cualquier bloqueo que ocurra dentro del manejador de errores (y es posible que espere algo si hay registro) sería una fuente potencial de interbloqueos.


Para ser honesto, los errores de señalización de eventos me parecen escalofriantes.

Hay un desacuerdo entre los campamentos en torno a devolver los códigos de estado y arrojar excepciones. Para simplificar (en gran medida): el campo de código de estado dice que lanzar excepciones coloca la detección y el manejo del error demasiado lejos del código que causa el error. El límite de lanzamiento de excepciones indica que los usuarios olvidan verificar los códigos de estado y las excepciones imponen el manejo de errores.

Los errores como eventos parecen ser lo peor de ambos enfoques. La limpieza del error está completamente separada del código que causa el error, y la notificación del error es completamente voluntaria. Ay.

Para mí, si el método no cumplió con su contrato implícito o explícito (no hizo lo que se suponía que debía hacer), una excepción es la respuesta adecuada. Lanzar la información que necesita en la excepción parece razonable en este caso.


Si piensas en términos de "Errores" y "Advertencias", he tenido mucha suerte al reservar eventos para la categoría "Advertencia" y Excepciones para la categoría "Errores".

El razonamiento aquí es que los eventos son opcionales. Nadie tiene un arma en la cabeza que te obliga a manejarlos. Probablemente esté bien para las advertencias, pero cuando tienes errores genuinos, debes asegurarte de que se tomen un poco más en serio. Deben manejarse las excepciones, o brotarán y crearán un mensaje desagradable para el usuario.

Con respecto a su pregunta sobre el Gran Objeto : definitivamente no está pasando grandes objetos, pero eso no significa que no pueda pasar referencias a objetos grandes. Hay mucho poder en la capacidad de hacer eso.

Como una adición, no hay nada que deje de plantear un evento además de la excepción, pero nuevamente: si tiene un error genuino, quiere algo para obligar al desarrollador del cliente a manejarlo.


Tenemos un objeto Error de base y ErrorEvent que usamos con el patrón de comando en nuestro marco para manejar errores no críticos (por ejemplo, errores de validación). Al igual que las excepciones, las personas pueden escuchar la base ErrorEvent o un ErrorEvent más específico.

También hay una diferencia significativa entre tus dos fragmentos.

if resource.FreeLotsOfMemory () borra el valor de StatusProperty en lugar de simplemente establecerlo en nulo, su variable temporal mantendrá un objeto no válido cuando OddException se crea y se lanza.

La regla de oro es que las Excepciones solo deben arrojarse en situaciones no recuperables. Realmente me gustaría que C # respaldara una cláusula de Throws que es lo único que realmente extraño de Java.


El primer fragmento debería ser probablemente

resource = AllocateLotsOfMemory(); if (SomeCondition()) { try { OnOddError(new OddErrorEventArgs(resource.StatusProperty)); return; } finally { resource.FreeLotsOfMemory(); } }

de lo contrario, no liberará sus recursos cuando el controlador de eventos arroje una excepción.

Como dijo Mike Brown, el segundo fragmento también tiene un problema si resource.FreeLotsOfMemory() equivoca con el contenido de resource.StatusProperty lugar de establecerlo en null .