Instrucción que es ignorada

Iniciado por zonahurbana, 23 Junio 2015, 03:21 AM

0 Miembros y 1 Visitante están viendo este tema.

zonahurbana

La verdad es que tengo un poco de experiencia usando Java y C#, y aunque aún no me acostumbro a la sintaxis de VB, lo siguiente me parece muy extraño.

1. La imagen siguiente muestra la instanciación de un objeto de mi clase Conexion (la estoy creando con la intención de facilitarme las cosas para futuras conexiones).
Le indico el nombre de la BD e invoco un método para hacer uso de dicho objeto.

(En el constructor creo un SqlConnection y un SqlAdapter en base a tal conexión)

2. Este es el método invocado desde lo que se muestra en la imagen 1 (que sería el evento Load de mi formulario). Y donde aparece la flecha es a donde aparentemente nunca se llega. El MessageBox nunca muestra el número 2. Antes de invocar a consultar estaba un MessageBox que mostraba el "1" y sí que sale, pero no el "2".


3. Este método consultar está dentro de mi clase Conexion. Se muestra "1a" y "1b" pero "1c" jamás se muestra. Mientras se muestran estos MessageBox el formulario (que es para editar/agregar productos) no se muestra (solo se ve el form principal desde el que se invoca).
Luego de que acepto el mensaje "1b", aparece el dichoso formulario y sin congelarse funciona bien. ¡ ¿Pero qué pasó con "1c" y "2" y "3"? !


Espero puedan darme una ayuda.
Gracias.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

zonahurbana

Soy un tipo realmente tonto :silbar:

No estaba inicializando el objeto DataTable.

De todas formas, si yo no usaba un Try Catch el programa no me advertía.
¿Por qué? En Java algunas excepciones deben tratarse obligatoriamente con un try/catch, y otras no, pero si ocurren, se notifica.

¿En VB tengo que adivinar qué instrucciones pueden generar excepciones?
¿O tal vez exagerar y encerrar todo en Try Catch's?

Gracias :s
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

Eleкtro

#2
Cita de: zonahurbana en 23 Junio 2015, 03:42 AM¿Por qué? En Java algunas excepciones deben tratarse obligatoriamente con un try/catch, y otras no, pero si ocurren, se notifica.

¿En VB tengo que adivinar qué instrucciones pueden generar excepciones?

No, cómo en Java, si no controlas una excepción, dicha excepción se lanzará/notificará.

Lo que te ocurre es debido a estos dos motivos:
1. Estás compilando la app bajo x64 (o AnyCPU)
2. Estás llamando al método que provoca dicha excepción (consultartipos) precisamente en la parte crítica de la inicialización y creación de la ventana del form.

El problema es que cuando esas dos condiciones se dan (la primera condición no la puedo confirmar si no lo especificas, pero voy a suponer que si), el debugger de VisualStudio es incapaz de controlar correctamente las excepciones que se provoquen durante el evento Form.Load bajo una aplicación x64/Neutral, por ende, nunca debes añadir código "inseguro" al método que se suscribe al evento Form.Load cómo estás haciendo aquí, ya que cualquier posible excepción será encontrada pero el tipo de excepción y el mensaje de error no te será notificado correctamente en la IDE (a menos que compiles la aplicación bajo x86):

Citar

Generalmente debes evitar usar ese método para añadir la lógica de tu código; primero deja que se cargue la ventana, y entonces, si hay alguna excepción se te notificará correctamente.

El evento digamos "After Load" sería el evento Form.Shown:

Código (vbnet) [Seleccionar]
public class form2: inherits form

   Private Sub Form2_Shown(ByVal sender As Object, ByVal e As EventArgs) _
   Handles MyBase.Shown

       ' Causar una excepción intencionada:
       Dim [error] As Integer = Convert.ToInt32("Hello World!")

   End Sub

end class


Tambien puedes usar el constructor de la class si prefieres inicializar lo que tengas que inicializar antes de cargar la ventana del Form, aquí las excepciones también te serán notificadas correctamente.

Código (vbnet) [Seleccionar]
public class form2: inherits form

   Public Sub New()

       ' This call is required by the designer.
       InitializeComponent()

       ' Add any initialization after the InitializeComponent() call.

       ' Causar una excepción intencionada:
       Dim [error] As Integer = Convert.ToInt32("Hello World!")

   End Sub

end class


EDITO:
Lo que yo suelo hacer cuando me encuentro en circunstancias "inseguras" es cargar el form de manera "invisible" y luego en el evento Form.Shown devolverle la visibilidad al Form:

( Solo es un tip, nada realmente importante )

Código (vbnet) [Seleccionar]
Public Class Form2 : Inherits Form

   Private Sub Form2_Load(ByVal sender As Object, ByVal e As EventArgs) _
   Handles MyBase.Load

       Me.Opacity = 0.0R

   End Sub

   Private Sub Form2_Shown(ByVal sender As Object, ByVal e As EventArgs) _
   Handles MyBase.Shown

       Try ' Causar una excepción intencionada:
           Dim [error] As Integer = Convert.ToInt32("Hello World!")

       Catch ex As Exception
           Throw

       End Try

       Me.Opacity = 1.0R

   End Sub

End Class


Saludos!








zonahurbana

Cita de: Eleкtro en 23 Junio 2015, 04:17 AM
Lo que te ocurre es debido a estos dos motivos:
1. Estás compilando la app bajo x64 (o AnyCPU)
2. Estás llamando al método que provoca dicha excepción (consultartipos) precisamente en la parte crítica de la inicialización y creación de la ventana del form.
¿Si compilo bajo x64 significa que el Release de la aplicación solo podría ejecutarse en ordenadores de 64 bits? Una vez leí que x86 era lo mismo que x32, pero mi ordenador es de 64 bits y al abrir el proyecto se muestra esto:


Cita de: Eleкtro en 23 Junio 2015, 04:17 AM[...] nunca debes añadir código "inseguro" al método que se suscribe al evento Form.Load cómo estás haciendo aquí, ya que cualquier posible excepción será encontrada pero el tipo de excepción y el mensaje de error no te será notificado correctamente en la IDE [...]

Generalmente debes evitar usar ese método para añadir la lógica de tu código; primero deja que se cargue la ventana, y entonces, si hay alguna excepción se te notificará correctamente.

El evento digamos "After Load" sería el evento Form.Shown:
[...]
En Java por alguna razón me acostumbré a escribir "código inicial" para los formularios en el constructor... pero como en VC++ al dar doble click sobre el formulario cargaba un método asociado al evento Load, creí que era lo correcto.

Cita de: Eleкtro en 23 Junio 2015, 04:17 AMTambien puedes usar el constructor de la class
Sí lo intenté, pero el contenido de la ventana no cargaba. Luego noté que hacía falta usar InitializeComponent(), como usted lo menciona.

Respecto a lo que escribió en su post al editar... ese tip lo hace considerando de que quiero escribir "código inicial" que pueda cerrar la ventana en algunos casos y que quiero que la ventana no llegue a observarse nunca si tales casos ocrreun, ¿verdad?

Muchas gracias por responder.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

Eleкtro

#4
Cita de: zonahurbana en 26 Junio 2015, 03:14 AM¿Si compilo bajo x64 significa que el Release de la aplicación solo podría ejecutarse en ordenadores de 64 bits?

Si compilas para x64 significa que estás haciendo la app compatible unicamente para Windows de 64 Bits, ya estés generando la compilación en modo Debug o en modo Release (obvio)




Cita de: zonahurbana en 26 Junio 2015, 03:14 AMUna vez leí que x86 era lo mismo que x32

x86 = 32 Bits.
x64 = 64 Bits.

x32 = NADA.
Es un término incorrecto que tiende a ser utilizado en el sentido de querer referirse a "32-bit", pero por simple desconocimiento del término adecuado.
El término x32 tendría sentido por ejemplo si estuvieramos hablando de Linux (x32 ABI).




Cita de: zonahurbana en 26 Junio 2015, 03:14 AMmi ordenador es de 64 bits y al abrir el proyecto se muestra esto

Ahá, es por que has elegido el modo Release a 32 Bits.

Puedes modificar la arquitectura a 64 Bits o Neutral (AnyCPU) en cualquier momento, desde ahí y también en la pestaña "Compile" de las propiedades de la solución de Visual Studio (En el explorador de soluciones -> Click derecho en el nombre de la solución "WES II" -> "Properties").

Nota: Si compilas en modo Neutral (es decir, AnyCPU), cómo estás bajo un Windows de 64 Bits entonces se te ejecutará la versión de 64 Bits (aunque, cabe mencionar que se puede especificar que haga lo opuesto).




Cita de: zonahurbana en 26 Junio 2015, 03:14 AMEn Java por alguna razón me acostumbré a escribir "código inicial" para los formularios en el constructor... pero como en VC++ al dar doble click sobre el formulario cargaba un método asociado al evento Load, creí que era lo correcto.

No, no es incorrecto, simplemente es innecesario ...mientras las circunstancias no requieran que añadas un Conctructor.

Ten en cuenta que Visual Studio es la IDE más completa, elaborada y optimizada para el desarrollador (indiferentemente de sus lenguajes soportados), la IDE siempre va a intentar automatizarte las tareas más comunes... cómo la que has comentado, pero eso no significa que manipular el código auto-generado por Visual Studio sea algo incorrecto, siempre que sepas lo que estás haciendo, claro está.

Cita de: zonahurbana en 26 Junio 2015, 03:14 AMSí lo intenté, pero el contenido de la ventana no cargaba. Luego noté que hacía falta usar InitializeComponent(), como usted lo menciona.

Claro, si te fijas verás que el método InitializeComponent es un método que contiene código auto-generado que está en la Class X.Designer.vb (donde "X" sería el nombre del Form), donde se inicializan todos los objetos/controles del Form y se le asignan los valores de las propiedades por defecto y las que hayas modificado en tiempo de diseño (en el constructor de la GUI), si no llamas a ese método ...entonces no hay Form xD.

Por si no lo sabias, es suficiente con que escribas public sub new, le das a la tecla Enter, y Visual Studio ya te genera este código:

Código (vbnet) [Seleccionar]
Public Sub New()

   ' This call is required by the designer.
   InitializeComponent()

   ' Add any initialization after the InitializeComponent() call.

End Sub


El mismo "truco" (si se le puede llamar así) también lo puedes aplicar al declarar implementaciones, por ejemplo:

Escribir public class form2 : implements idisposable + pulsar tecla Enter, generará este código:

Código (vbnet) [Seleccionar]
Public Class form2 : Implements idisposable

#Region "IDisposable Support"
   Private disposedValue As Boolean ' To detect redundant calls

   ' IDisposable
   Protected Overridable Sub Dispose(disposing As Boolean)
       If Not Me.disposedValue Then
           If disposing Then
               ' TODO: dispose managed state (managed objects).
           End If

           ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
           ' TODO: set large fields to null.
       End If
       Me.disposedValue = True
   End Sub

   ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
   'Protected Overrides Sub Finalize()
   '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
   '    Dispose(False)
   '    MyBase.Finalize()
   'End Sub

   ' This code added by Visual Basic to correctly implement the disposable pattern.
   Public Sub Dispose() Implements IDisposable.Dispose
       ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
       Dispose(True)
       GC.SuppressFinalize(Me)
   End Sub
#End Region

End Class





Cita de: zonahurbana en 26 Junio 2015, 03:14 AMese tip lo hace considerando de que quiero escribir "código inicial" que pueda cerrar la ventana en algunos casos y que quiero que la ventana no llegue a observarse nunca si tales casos ocrreun, ¿verdad?

Sí, por que de otro modo, si intentases cerrar el Form en el Constructor no podrías cerrarlo ya que al llamar al método Form.Close se intentaría liberar (llamando internamente al método Form.Dispose) un Form que todavía no ha sido inicializado, y eso lanzaría una excepción.

Y si lo intentases en el método que controla el evento Form.Load bajo una app x64 y ocurriese la excepción que mencionaste pues... ya sabes lo que pasaría.

Así que ...sí, pienso que lo mejor sería ejecutar esas instrucciones en el método que controla el evento Form.Shown.

De todas formas, si ahora ya estás controlando la excepción que mencionaste, es decir, si la tienes encerrada un bloque Try/Catch, entonces si que puedes usar el evento Form.Load para cerrar el form (sin que sea visible ni nada), o suplantar el método Form.OnLoad o Form.OnControlCreated, cómo te muestro en este ejemplo:

Código (vbnet) [Seleccionar]
Public NotInheritable Class Form2 : Inherits Form

   <DebuggerStepThrough>
   Protected Overrides Sub OnLoad(e As EventArgs)

       Me.MyMethod()
       MyBase.OnLoad(e)

   End Sub

   <DebuggerStepThrough>
   Private Sub MyMethod()

       Try
           Throw New Exception(message:="Excepción intencionada.")

       Catch ' ex As Exception
           MyBase.Close()

       End Try

   End Sub

End Class


Saludos!








zonahurbana

Cita de: Eleкtro en 26 Junio 2015, 06:58 AM
Si compilas para x64 significa que estás haciendo la app compatible unicamente para Windows de 64 Bit
¿Y si compilo para x86 será compatible tanto para windows de 32 como 64 bits?




Respecto a modificar la arquitectura, por el contrario, no debería hacerlo, ¿verdad?
Usted anteriormente comentó que si es de x64 no detecta correctamente las excepciones.




Cita de: Eleкtro en 26 Junio 2015, 06:58 AMTen en cuenta que Visual Studio es la IDE más completa, elaborada y optimizada para el desarrollador (indiferentemente de sus lenguajes soportados), la IDE siempre va a intentar automatizarte las tareas más comunes... cómo la que has comentado, pero eso no significa que manipular el código auto-generado por Visual Studio sea algo incorrecto, siempre que sepas lo que estás haciendo, claro está.

Por si no lo sabias, es suficiente con que escribas public sub new, le das a la tecla Enter, y Visual Studio ya te genera este código [...]
Okay. Me parece que había copiado el constructor que tenía en otra clase para evitar escribir.




Cita de: Eleкtro en 26 Junio 2015, 06:58 AMDe todas formas, si ahora ya estás controlando la excepción que mencionaste, es decir, si la tienes encerrada un bloque Try/Catch, entonces si que puedes usar el evento Form.Load para cerrar el form (sin que sea visible ni nada), o suplantar el método Form.OnLoad o Form.OnControlCreated, cómo te muestro en este ejemplo [...]
En conclusión, VB sí detecta las excepciones que ocurren y que no son controladas, pero no lo hace si dichas excepciones ocurren en el evento Load.
Muy aparte, si uso try/catch su funcionamiento siempre es adecuado, es decir, advierte excepciones en cualquier parte del prgrama.

Gracias nuevamente.

PD: He creado una clase Conexion para usarla en todo lo referente a consultar/ejecutar operaciones sobre una BD en SqlServer. Tengo algunas preguntas sobre qué es lo más recomendable, creo que haré un nuevo hilo para ello.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

Eleкtro

#6
Cita de: zonahurbana en 26 Junio 2015, 08:00 AM¿Y si compilo para x86 será compatible tanto para windows de 32 como 64 bits?

Si, un S.O de 64 Bits puede correr aplicaciones de 32 Bits.




Cita de: zonahurbana en 26 Junio 2015, 08:00 AMRespecto a modificar la arquitectura, por el contrario, no debería hacerlo, ¿verdad?

En tu caso no es necesario modificarla. deberías compilar en AnyCpu o en x86.




Cita de: zonahurbana en 26 Junio 2015, 08:00 AMUsted anteriormente comentó que si es de x64 no detecta correctamente las excepciones.

En conclusión, VB sí detecta las excepciones que ocurren y que no son controladas, pero no lo hace si dichas excepciones ocurren en el evento Load.

No dije eso exactamente, lo que intenté explicarte es que debido a la naturaleza por parte de cómo el compiler trabaja durante ese paso específico y bajo x64, si añades código "inseguro" en el método suscrito al evento Form.Load y se produce una excepción, aunque la exepción se intercepte internamente, no te saldrá ningún mensaje de error en Visual Studio, y con eso pretendía que entendieras que al hacer lo que estabas haciendo, estabas siguiendo una mala práctica que debes evitar.

De todas formas cabe mencionar que cuando eso ocurre, la linea de la instrucción se resaltará (se eligirá esa linea aunque no aparezca ningún mensaje de error), y siempre puedes revisar el call stack manualmente para analizar lo ocurrido e intentar depurarlo.

Pero simplemente no uses ese evento Form.Load para añadir código de ese tipo, usa el evento Form.Shown por ejemplo, cómo ya dije.




Cita de: zonahurbana en 26 Junio 2015, 08:00 AMPD: He creado una clase Conexion para usarla en todo lo referente a consultar/ejecutar operaciones sobre una BD en SqlServer. Tengo algunas preguntas sobre qué es lo más recomendable, creo que haré un nuevo hilo para ello.

No me manejo con SQL, pero espero que puedas resolver el problema que tengas.

Saludos!








zonahurbana

Cita de: Eleкtro en 26 Junio 2015, 09:49 AM[...]Pero simplemente no uses ese evento Form.Load para añadir código de ese tipo, usa el evento Form.Shown por ejemplo, cómo ya dije.
[...]

Como había corregido el problema continuaba usando el evento Load, pero ocurrió nuevamente otro error... no comprendía la razón, cambié el evento por Shown y la excepción saltó a la vista. Muchas gracias !

PD: En VC++ y Java, si necesitaba cambiar un evento por otro debía borrar el método autogenerado y volver a crear otro con ayuda del IDE. En VB ha bastado con cambiar el nombre del evento textualmente. La keyword "Handles" parece muy útil.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...