https://foro.gambas-es.org/viewtopic.php?f=5&t=454
-----------------------------------
GambasLinux
Miercoles, 24 Febrero 2010, 15:33

Control De Errores Global
-----------------------------------
Hola compañeros, Saludos a todos, y Gracias por las ideas que me han dado muy amablemente.

Esta vez me asalta esta inquietud:

Necesito crear un modulo que me capture los errores que puedan suceder en mi aplicación, pero a nivel global no procedual pues conozco de las sentencias:

TRY  Ejemplo: 

[code linenumbers=false syntax=gambas]TRY KILL "/tmp/prueba/"
IF ERROR THEN Message.error("No fue posible eliminar")
[/code]


[code linenumbers=false syntax=gambas]FINALLY

   'ordenes que pueden producir en algún momento errores, se ejecuta halla o no error

CATCH
   'se ejecuta si sucede un error, y va al final del procedimiento
   ...
END
[/code]
El los contenedores[url=http://gambasdoc.org/help/comp/gb.qt/form?es]Form(qb.qt) no veo un evento ONERROR  o ERROR donde pueda GOLBALMENTE intersertarlos.

Al lograrlo también me gustaría recibir:

1. El nombre del Procedimiento donde se produjo el error 
2. La linea de código donde se produjo

Gracias por la Guía que me puedan dar.

PD:

Recuerden Intersertar errores GLOBAL que se pueda producir en cualquier Procedimiento/Función de toda la aplicación, y NO escritura LOCAL en Lineas o Bloques en Procedimientos.


-----------------------------------
jguardon
Miercoles, 24 Febrero 2010, 17:45

Re: Control De Errores Global
-----------------------------------
Interesante. Pero mi experiencia intentando algo parecido no tuvo éxito en su momento...

Pensé que la clase Error ([u]no[/u] ERROR en mayúsculas) la podía usar para lo que dices pasando el valor de sus propiedades a un formulario diseñado al efecto:

En un procedimiento cualquiera:

[code linenumbers=false syntax=gambas]
' ...
CATCH
    FormError.Run(Error.Text, Error.Where)[/code]

Y en el form "FormError":

[code linenumbers=false syntax=gambas]PRIVATE SUB Run(texto AS String, linea AS String)

Label1.Text = texto
Label2.Text = linea
Me.Show()

END[/code]

Pero no funciona. Según Benoît, porque la clase [i]Error[/i] es virtual y sus valores se pierden nada más salir del procedimiento que los genera.

Hasta ahora no he encontrado la forma de solucionarlo ni tampoco él me ha indicado cómo, si es que es posible.

Saludos


-----------------------------------
soplo
Miercoles, 24 Febrero 2010, 18:24

Re: Control De Errores Global
-----------------------------------
Un tema interesante.

A ver como sale esto:

Me creo una clase ClaseError con el siguiente contenido:
[quote]inherits error
[/quote]

Ahora en un módulo de la aplicacion marcado como clase de inicio hago lo siguiente
[code linenumbers=false syntax=gambas]Public Er as new ErrorClass 'defino Er como global

public sub Main()
Dim F as new Formulario Principal
F.show
end[/code]

Ahora en cada formulario o clase  debería haber una única función para tratar el error. Es muy cierto lo que dice JGuardón. El error persiste en el formulario o clase pero luego muere. Lo que pasa es que el error puede propagarse dentro del formulario o clase.

Osea que si yo tengo una función que tiene un catch y un finally y en esa función llamo a otra función que no lo tiene y esta  llama a otra función que tampoco lo tiene (una función nieto) y en esta ocurre el error lo que ocurri&#341;a es que el error se propagará y saltará en el catch inicial.

Osea que si yo programo ese catch inicial debería valer.
Este debería se el catch
[code linenumbers=false syntax=gambas]Er.Backtrace=error.backtrace 'pasar la pila de llamadas (que función hija de función, hija de función, de que clase)
Er.Class=error.class 'en que clase ha ocurrido el error
Er.Code=error.Code 'el código del error
Er.Text=error.text 'el mensaje del error
Er.Where=error.where 'línea donde ocurrió el error
[/code]

En la clse ClaseError podríamos crear propiedades adicionales o métodos apropiados para el tratamiento de ese error según queramos.
El catch y el finaly por tanto deberían ir en alguna función de tipo superior. No puedo probar ahora pero la cosa sería que al ocurrir un error en alguna función que no tiene tratamiento de error salte a la función padre o abuelo o lo que sea. El error terminará cuando corresponda pero la clase ErrorClase que contiene toda la información persistirá.

Creo que eso o algo muy parecido deberia funcionarl


-----------------------------------
fabianfv
Miercoles, 24 Febrero 2010, 21:38

Re: Control De Errores Global
-----------------------------------
El problema que le veo a este planteamiento es que los errores no persisten en formularios o clases, sino que se propagan únicamente de la rutina que fue llamada a la rutina que la llamó (y esto puede darse en varios niveles de anidamiento), pero no es común ni acertado escribir código que tenga un anidamiento de ese tipo (una rutina que llama a otra, que a la vez llama a una tercera, que llama a una cuarta...)

Aún si alguien escribe su código de ese modo la rutinas que no fueran parte de esos anidamientos no estarían cubiertas.

Para que la idea funcione debería escribirse una clase de inicio (o módulo) que [b]incluya un método puente[/b] y una [b]interfaz de métodos públicos[/b] que llaman al método puente. Éste a su vez deberá llamar al método privado que correponda ([b]interfaz de métodos privados[/b]). [b]El método puente debe contener la sentencia CATH[/b] que trata los errores (directamente o través de otro método).

Ejemplo:


[code linenumbers=false syntax=gambas]
'Clase de inicio

PRIVATE CONST PRIV_METODO_1 AS BYTE =  1
PRIVATE CONST PRIV_METODO_2 AS BYTE =  2
PRIVATE CONST PRIV_METODO_3 AS BYTE =  3

PRIVATE $PropiedadMiembro AS tipo_dato_1

PROPERTY PropiedadMiembro AS tipo_dato_1

PRIVATE FUNCTION PropiedadMiembro_Read () AS tipo_dato_1
  RETURN $PropiedadMiembro
END

PRIVATE SUB PropiedadMiembro_Write (Value AS tipo_dato_1)
  $PropiedadMiembro = Value
END

'********************************
'* Interfaz de métodos públicos *
'********************************

PUBLIC SUB Metodo_1 ()
  MetodoPuente (PRIV_METODO_1)
END

PUBLIC SUB Metodo_2 ()
  MetodoPuente (PRIV_METODO_2)
END

PUBLIC SUB Metodo_3 ()
  MetodoPuente (PRIV_METODO_3)
END

'***********
'* Puente *
'***********

PRIVATE MetodoPuente (arg AS Byte)

  SELECT CASE arg
     CASE PRIV_METODO_1
         PrivMetodo_1
     CASE PRIV_METODO_2
         PrivMetodo_2
     CASE PRIV_METODO_3
         PrivMetodo_3
  END SELECT

  CATCH
     'Hacer algo con el error
END

'********************************
'* Interfaz de métodos privados *
'********************************

PRIVATE SUB PrivMetodo_1 ()
   'Quiero hacer algo útil  
END

PRIVATE SUB PrivMetodo_2 ()
   'Quiero hacer algo útil  
END

PRIVATE SUB PrivMetodo_2 ()
   'Quiero hacer algo útil  
END
[/font]
[/code]

Esto no lo he probado sólo es una deducción lógica que espero sea acertada.

Saludos cordiales.


-----------------------------------
soplo
Jueves, 25 Febrero 2010, 19:29

Re: Control De Errores Global
-----------------------------------
Bueno, una cosa es que se pueda hacer que por poder parece que se puede y aquí se han expuesto algunas ideas, pero no creo que sae una buena idea (aunque yo no tengo el patrimonio de la razón obviamente).

Quizá mejor solución es crear una clase con un formulario y algunas propiedades para que en caso de error (en los catch respectivos) se haga una llamada a esa clase y se informe el error o se haga alguna cosa. En mi opinión es suficiente con el message, pero creo que ese tipo de cosas a la larga dan mas problemas que otra cosa. En mi opinión cada rutina debe llevar su propio control de errores, pero solo es una opinión claro.

 :mryellow:


-----------------------------------
fabianfv
Jueves, 25 Febrero 2010, 21:02

Re: Control De Errores Global
-----------------------------------
[quote]
En mi opinión cada rutina debe llevar su propio control de errores, pero solo es una opinión claro.
[/quote]
Comparto esa opinión. Sólo que en un programa hay rutinas que realmente no necesitan capturar posibles errores (las que son extremadamente simples) o aquellas en las que puede evitarse la posibilidad de error por ejemplo:
[code linenumbers=false syntax=gambas]
IF Exists(FileName) THEN... .
[/code]
Claramente, una única rutina de tratamiento de errores para toda una clase (que fácilmente puede contener más que unos pocos métodos) sería demasiado extensa o compleja. De modo que las rutinas que lo necesiten deberían tener su propio código para manejar sus errores.

Una aclaración más. Hay errores no tienen por qué ser informados al usuario (hacerlo incluso podría significar un problema de seguridad), especialmente aquellos que la aplicación puede solventar sin intervención del usuario o aquellos que desde el principio conocemos que el usuario no podrá resolver.


