try manejo excepciones catch delphi exception-handling

catch - manejo de excepciones en delphi



¿Cómo debo volver a plantear una excepción de Delphi después de iniciar sesión? (7)

¿Conoces una forma de atrapar, registrar y volver a subir la excepción en el código Delphi? Un simple ejemplo:

procedure TForm3.Button1Click(Sender: TObject); begin try raise Exception.Create(''Bum''); except on E: Exception do begin MyHandleException(E); end; end; end; procedure TForm3.MyHandleException(AException: Exception); begin ShowMessage(AException.Message); LogThis(AException.Message); // raise AException; - this will access violate end;

Así que tengo que volver a subirlo en el bloque excepto, pero me preguntaba si hay una mejor manera de escribir mi propio método para manejar y (en condiciones específicas) volver a plantear excepciones.


Debería poder usar el comando Raise solo para volver a subir la excepción:

begin MyHandleException(E); Raise; end;


Lo siguiente funcionará, pero por supuesto no es ideal por dos razones:

  • La excepción se plantea desde un lugar diferente en la pila de llamadas.
  • No obtiene una copia exacta de la excepción, especialmente aquellas clases que agregan atributos. Es decir, tendrá que copiar explícitamente los atributos que necesita.
  • La copia de atributos personalizados puede complicarse debido a la verificación de tipos requerida.

.

procedure TForm3.MyHandleException(AException: Exception); begin ShowMessage(AException.Message); LogThis(AException.Message); raise ExceptClass(AException.ClassType).Create(AException.Message); end;

Los beneficios son que conserva la clase de excepción original y el mensaje (y cualquier otro atributo que desee copiar).

Lo ideal es llamar a System._RaiseAgain , pero, por desgracia, es una rutina de "compilación mágica" y solo se puede llamar mediante raise; .


Puede adquirir el objeto de excepción antes de llamar a su controlador y mantener el controlador en sí mismo un liner. Sin embargo, todavía tiene una gran cantidad de carga "Try / Except / Do / End".

Procedure MyExceptionHandler(AException: Exception); Begin Log(AException); // assuming it accepts an exception ShowMessage(AException.Message); raise AException; // the ref count will be leveled if you always raise it End; Procedure TForm3.Button1Click(Sender: TObject); Begin Try Foo; Except On E:Exception Do MyExceptionHandler(Exception(AcquireExceptionObject)); End; End;

Sin embargo, si lo único que desea hacer es deshacerse del código de manejo de errores repetitivo en los controladores de eventos, podría intentar esto:

Procedure TForm3.ShowException(AProc : TProc); Begin Try AProc; Except On E:Exception Do Begin Log(E); ShowMessage(E.Message); End; End; End;

Reduciendo su código de controlador de eventos a esto:

Procedure TForm3.Button1Click(Sender: TObject); Begin ShowException(Procedure Begin // anon method Foo; // if this call raises an exception, it will be handled by ShowException''s handler End); End;

También puede hacer que funcione para funciones, usando funciones parametrizadas:

Function TForm3.ShowException<T>(AFunc : TFunc<T>) : T; Begin Try Result := AFunc; Except On E:Exception Do Begin Log(E); ShowMessage(E.Message); End; End; End;

Y hacer que ShowException devuelva un valor (actuando como un passthru):

Procedure TForm3.Button1Click(Sender: TObject); Var V : Integer; Begin V := ShowException<Integer>(Function : Integer Begin // anon method Result := Foo; // if this call raises an exception, it will be handled by ShowException''s handler End); End;

O incluso haciendo que el procedimiento anon toque directamente la (s) variable (s) del ámbito externo:

Procedure TForm3.Button1Click(Sender: TObject); Var V : Integer; Begin ShowException(Procedure Begin // anon method V := Foo; // if this call raises an exception, it will be handled by ShowException''s handler End); End;

Existen algunas limitaciones en la interacción de variables desde el interior del cuerpo de la función anónima y las definidas en el ámbito externo, pero para casos simples como estos, estará más que bien.


Puede intentar usar (system.pas):

function AcquireExceptionObject: Pointer;

AcquireExceptionObject devuelve un puntero al objeto de excepción actual y evita que el objeto de excepción sea desasignado cuando se cierra el controlador de excepción actual.

Nota: AcquireExceptionObject incrementa el recuento de referencias del objeto de excepción. Asegúrese de que el recuento de referencias disminuya cuando ya no se necesite el objeto de excepción. Esto sucede automáticamente si usa el objeto de excepción para volver a generar la excepción. En todos los demás casos, cada llamada a AcquireExceptionObject debe tener una llamada correspondiente a ReleaseExceptionObject. Las secuencias de AcquireExceptionObject / ReleaseExceptionObject se pueden anidar.


Si desea volver a plantear la excepción solo bajo ciertas condiciones, escriba

procedure TForm3.Button1Click(Sender: TObject); begin try raise Exception.Create(''Bum''); except on E: Exception do begin if MyHandleException(E) then raise; end; end; end; function TForm3.MyHandleException(AException: Exception): boolean; begin ShowMessage(AException.Message); result := true/false; end;


Siguiendo con la publicación de Craig Young, utilicé algo similar al siguiente código con éxito. Puede conservar la ubicación de excepción original utilizando el identificador "at" con la función ExceptAddr. El tipo de clase de excepción original y la información también se conservan.

procedure MyHandleException(AMethod: string); var e: Exception; begin e := Exception(AcquireExceptionObject); e.Message := e.Message + '' raised in '' + AMethod; raise e at ExceptAddr; end; try ... except MyHandleException(''MyMethod''); end;


Viejo tema pero, ¿qué pasa con esta solución?

procedure MyHandleException(AException: Exception); begin ShowMessage(AException.Message); AcquireExceptionObject; raise AException; end; procedure TForm1.Button1Click(Sender: TObject); begin try raise Exception.Create(''Bum''); except on E: Exception do MyHandleException(E); end; end;

Se basa en el primer código publicado por Eduardo.