Buscador

Código de clase y código cliente

Antes de comenzar a realizar pruebas con las clases que vayamos escribiendo, debemos explicar dos conceptos referentes a la escritura de código orientado a objeto, ya que en función del lugar desde el que sea manipulado, debemos distinguir entre código de clase y código cliente. 
• Código de clase. 
Se trata del código que escribimos para crear nuestra clase, y que se encuentra entre las palabras clave Class...End Class. 
• Código cliente. 
Se trata del código que hace uso de la clase mediante la acción de crear o instanciar objetos a partir de la misma. Aquí se englobaría todo el código que se encuentra fuera de la clase.

Organización de clases en uno o varios ficheros de código

Como ya se ha explicado en los temas sobre el lenguaje, una clase es uno de los tipos de contenedor lógico disponible dentro del entorno de .NET Framework, y su organización puede realizarse al igual que los módulos (Module) de código estándar del entorno, es decir, cada vez que añadimos una clase al proyecto utilizando el IDE, se crea por defecto, un fichero de código por clase. Sin embargo, también podemos incluir varias clases dentro del mismo fichero de código, o mezclar clases con módulos y otro tipo de contenedores lógicos, cambiando si es necesario el nombre del fichero, como ya se explicó en los apartados sobre el lenguaje. El ejemplo del Código fuente 219 muestra dos clases creadas dentro del mismo fichero.

' Fichero MisClases.VB
' ====================
Public Class Empleado
' código de la clase
' ......
' ......
End Class
Public Class Factura
' código de la clase
' ......
' ......
End Class
Código fuente 219

Creación de clases

Volvamos al ejemplo expuesto al comienzo de este tema, en el cuál, un programador necesitaba desarrollar los procesos de un empleado dentro de una aplicación de gestión empresarial. Recordemos que se planteaba el problema de que ante el crecimiento del programa, el mantenimiento del código, al enfocarse de modo procedural, podía volverse una tarea realmente difícil. Vamos a replantear este diseño, encauzándolo bajo una perspectiva orientada a objeto, que nos permita un uso más sencillo del código y un mantenimiento también más fácil. Para lo cual desarrollaremos una clase que contenga todas las operaciones a realizar por el empleado; en definitiva, crearemos la clase Empleado, cuyo proceso describiremos a continuación. Iniciaremos en primer lugar VS.NET, creando un proyecto de tipo consola. A continuación seleccionaremos el menú Proyecto + Agregar clase, que nos mostrará la ventana para agregar nuevos elementos al proyecto. El nombre por defecto asignado por el IDE para la clase será Class1; cambiaremos dicho nombre por Empleado, y pulsaremos Abrir. Ver Figura 106.
Figura 106. Añadir una clase a un proyecto.
Se creará de esta forma un nuevo fichero de código (EMPLEADO.VB), mostrándose el editor de código con su contenido. Observemos en este sentido, que la definición de una clase se realiza utilizando las palabras clave Class...End Class; entre estas palabras escribiremos el código de la clase. Ver Código fuente 218.

Public Class Empleado
End Class
Código fuente 218

Análisis y diseño orientado a objetos

Antes de comenzar la escritura del programa, se hace necesario realizar un análisis de los problemas a resolver, que nos permita identificar qué procesos debemos codificar. Si pretendemos además, abordar la programación utilizando un enfoque orientado a objetos, debemos emplear técnicas adecuadas a este tipo de programación.Para aunar todas las tendencias de análisis orientadas a objetos existentes, ha aparecido el Lenguaje Unificado de Modelado o UML (Unified Modeling Language), cuyo objetivo es proporcionar un verdadero sistema de análisis y diseño aplicado a objetos. 
La descripción de UML es algo que se encuentra fuera del alcance de este texto, por lo que recomendamos al lector consultar la documentación existente al respecto, de manera que pueda familiarizarse con este aspecto de la creación de un programa. A modo de breve recomendación podemos decir, que cuando se realiza un análisis basado en procedimientos, de los problemas planteados, se identifican los verbos como elementos de los procesos a trasladar a procedimientos y funciones. 
Sin embargo, cuando se trata de un análisis basado en objetos, se identifican en este caso los nombres existentes en los procesos, como elementos a trasladar a objetos. Tomemos el siguiente planteamiento: “Crear una aplicación en la que podamos realizar sobre una base de datos, las siguientes operaciones: añadir, borrar y modificar clientes. Por otro lado, será necesario crear facturas, grabando sus datos generales y calcular su importe total”. Analizando la exposición del anterior problema, si necesitáramos resolverlo mediante una aplicación con enfoque procedural, separaríamos los verbos para crear los siguientes procedimientos: AñadirCliente( ), BorrarCliente( ), ModificarCliente( ), GrabarFac( ), CalcularTotalFac( ). 
Si por el contrario efectuamos sobre la misma exposición, un análisis orientado a objetos, extraeríamos los siguientes nombres como los objetos a crear: Cliente, Factura. Para el objeto Cliente, definiríamos entre otras, las propiedades Nombre, Apellidos, Dirección, DNI, etc; creando para su comportamiento, los métodos Añadir( ), Borrar( ), Modificar( ), etc. Para el objeto Factura, definiríamos entre otras, las propiedades Número, Fecha, Importe, etc; creando para su comportamiento, los métodos Grabar( ), CalcularTotal ( ), etc. Una vez obtenido el correspondiente análisis, pasaremos a la siguiente fase del desarrollo, la escritura de las diferentes clases que van a componer nuestro programa, y que veremos a continuación.

Relaciones entre objetos - II

Utilización 

Hay situaciones en que un objeto utiliza a otro para realizar una determinada tarea, sin que ello suponga la existencia de una relación de pertenencia entre dichos objetos. Por ejemplo, un objeto Ventana puede utilizar un objeto Empleado para mostrar al usuario las propiedades del empleado, sin necesidad de que el objeto Empleado sea propiedad del objeto Ventana. Nótese la importante diferencia entre esta relación y la anterior, ya que aquí, el objeto Ventana a través de código, creará, o le será pasado como parámetro, un objeto Empleado, para poder mostrarlo en el área de la ventana. Para reconocer si existe esta relación entre dos objetos, debemos realizar un análisis sintáctico sobre la misma empleando la partícula “usa un”. Así, por ejemplo, la frase “Un objeto Ventana usa un objeto Empleado” devolvería verdadero. 

Reutilización 

Un objeto bien diseñado, puede ser reutilizado en otra aplicación de modo directo o creando una clase derivada a partir de él. Este es uno de los objetivos perseguidos por la OOP, aprovechar en lo posible el código ya escrito, ahorrando un considerable tiempo en el desarrollo de programas.

Relaciones entre objetos - I

Los objetos existentes en una aplicación se comunican entre sí mediante una serie de relaciones que describimos a continuación. 

Herencia 
Como acabamos de describir en el apartado sobre características de la OOP, cuando a partir de una clase existente, creamos una nueva clase derivada, esta nueva clase dispone de todas las propiedades y métodos de la clase base, mas el código propio que implemente. Para reconocer si existe esta relación entre dos objetos, debemos realizar un análisis sintáctico sobre la misma usando la partícula “es un”. Tomando como ejemplo los objetos Empleado, CiberEmpleado y Factura, podemos decir que sí hay una relación de herencia entre Empleado y CiberEmpleado, ya que al analizar la frase “Un objeto CiberEmpleado es un Empleado”, el resultado es verdadero. No ocurre lo mismo entre los objetos CiberEmpleado y Factura, ya que el análisis de la frase “Un objeto CiberEmpleado es una Factura”, devuelve falso. 

Pertenencia 
Los objetos pueden estar formados a su vez por otros objetos. Un objeto Factura puede estar compuesto por objetos CabeceraFactura, LineaFactura, etc. Se dice en este caso que hay una relación de pertenencia, puesto que existe un conjunto de objetos que pertenecen a otro objeto o se unen para formar otro objeto. A este tipo de relación se le denomina también Contenedora. Para reconocer si existe esta relación entre dos objetos, debemos realizar un análisis sintáctico sobre la misma usando la partícula “tiene un”. Así, por ejemplo, la frase “Un objeto Factura tiene un objeto LineaFactura” devolvería verdadero.

Relaciones entre objetos

Los objetos existentes en una aplicación se comunican entre sí mediante una serie de relaciones que describimos a continuación. Herencia Como acabamos de describir en el apartado sobre características de la OOP, cuando a partir de una clase existente, creamos una nueva clase derivada, esta nueva clase dispone de todas las propiedades y métodos de la clase base, mas el código propio que implemente. Para reconocer si existe esta relación entre dos objetos, debemos realizar un análisis sintáctico sobre la misma usando la partícula “es un”.

Jerarquías de clases

Como decíamos en un apartado anterior, uno de los fines de la OOP consiste en la clasificación del código; para ello se emplean jerarquías o árboles de clases, en los que a base de niveles, se muestra un conjunto de clases conectadas por una relación de herencia. Observemos el esquema de la Figura 105, en el que se muestra un ejemplo de la jerarquía de clases de medios de transporte.
Figura 105. Jerarquía de clases de medios de transporte. En esta representación de ejemplo, como nivel superior de la jerarquía o clase base estaría Medios de transporte, de la que se derivarían las clases Barco, Tren, Automóvil, y a su vez, de estas últimas, partirían nuevas clases hijas.

Herencia

Se trata de la característica más importante de la OOP, y establece que partiendo de una clase a la que denominamos clase base, padre o superclase, creamos una nueva clase denominada clase derivada, hija, o subclase. En esta clase derivada dispondremos de todo el código de la clase base, más el nuevo código propio de la clase hija, que escribamos para extender sus funcionalidades. A su vez podemos tomar una clase derivada, creando una nueva subclase a partir de ella, y así sucesivamente, componiendo lo que se denomina una jerarquía de clases, que explicaremos seguidamente. Existen dos tipos de herencia: simple y múltiple. 
La herencia simple es aquella en la que creamos una clase derivada a partir de una sola clase base, mientras que la herencia múltiple nos permite crear una clase derivada a partir de varias clases base. El entorno de .NET Framework sólo permite utilizar herencia simple, por lo que este es el tipo de herencia que podremos usar con el lenguaje VB.NET. Como ejemplo real de herencia, podemos usar la clase Coche como clase base; en ella reconocemos una serie de propiedades como Motor, Ruedas, Volante, etc., y unos métodos como Arrancar, Acelerar, Frenar, etc. Como clase derivada creamos CocheDeportivo, en la cuál, además de todas las características mencionadas para la clase Coche, encontramos propiedades y comportamiento específicos como ABS, Turbo, etc. Un ejemplo basado en programación consistiría en disponer de la ya conocida clase Empleado. Esta clase se ocupa, como ya sabemos, de las operaciones de alta de empleados, pago de nóminas, etc.; pero en un momento dado, surge la necesidad de realizar pagos a empleados que no trabajan en la central de la empresa, ya que se trata de comerciales que pasan la mayor parte del tiempo desplazándose. 
Para realizar dichos pagos usaremos Internet, necesitando el número de tarjeta de crédito y la dirección email del empleado. Resolveremos esta situación creando la clase derivada CiberEmpleado, que hereda de la clase Empleado, en la que sólo tendríamos que añadir las nuevas propiedades y métodos para las transacciones electrónicas, puesto que las operaciones tradicionales ya las tendríamos disponibles por el mero hecho de haber heredado de Empleado.

Características básicas de un sistema orientado a objeto - II

Encapsulación 
La encapsulación establece la separación entre el interfaz del objeto y su implementación, aportándonos dos ventajas fundamentales. Por una parte proporciona seguridad al código de la clase, evitando accesos y modificaciones no deseadas; una clase bien encapsulada no debe permitir la modificación directa de una variable, ni ejecutar métodos que sean de uso interno para la clase. Por otro lado la encapsulación simplifica la utilización de los objetos, ya que un programador que use un objeto, si este está bien diseñado y su código correctamente escrito, no necesitará conocer los detalles de su implementación, se limitará a utilizarlo. Tomando un ejemplo real, cuando nosotros utilizamos un objeto Coche, al presionar el acelerador, no necesitamos conocer la mecánica interna que hace moverse al coche, sabemos que el método Acelerar del coche es lo que tenemos que utilizar para desplazarnos, y simplemente lo usamos. Pasando a un ejemplo en programación, si estamos creando un programa de gestión y nos proporcionan un objeto Cliente que tiene el método Alta, y sirve para añadir nuevos clientes a la base de datos, no precisamos conocer el código que contiene dicho método, simplemente lo ejecutamos y damos de alta a los clientes en nuestra aplicación. 
Polimorfismo 
El polimorfismo determina que el mismo nombre de método, realizará diferentes acciones según el objeto sobre el que sea aplicado. Al igual que sucedía en la encapsulación, el programador que haga uso del objeto, no necesita conocer los detalles de implementación de los métodos, se limita a utilizarlos. Pasando a un ejemplo real, tomamos dos objetos: Pelota y VasoCristal; si ejecutamos sobre ambos el método Tirar, el resultado en ambos casos será muy diferente; mientras que el objeto Pelota rebotará al llegar al suelo, el objeto VasoCristal se romperá. En un ejemplo aplicado a la programación, supongamos que disponemos de los objetos Ventana y Fichero; si ejecutamos sobre ambos el método Abrir, el resultado en Ventana será la visualización de una ventana en el monitor del usuario; mientras que en el objeto Fichero, se tomará un fichero en el equipo del usuario y se dejará listo para realizar sobre él operaciones de lectura o escritura.

Características básicas de un sistema orientado a objeto - I

Para que un lenguaje o sistema sea considerado orientado a objeto, debe cumplir las características de los siguientes apartados. 

Abstracción 

La abstracción es aquella característica que nos permite identificar un objeto a través de sus aspectos conceptuales. Las propiedades de los objetos de una misma clase, pueden hacerlos tan distintos que sea difícil reconocer que pertenecen a una clase idéntica. No obstante, nosotros reconocemos a qué clase pertenecen, identificando además, si se trata de la misma clase para ambos. Ello es posible gracias a la abstracción. Tomemos como ejemplo dos objetos coche, uno deportivo y otro familiar; su aspecto exterior es muy diferente, sin embargo, cuando pensamos en cualquiera de ellos, sabemos que ambos pertenecen a la clase Coche, porque realizamos una abstracción o identificación mental de los elementos comunes que ambos tienen (ruedas, volante, motor, puertas, etc.). Del mismo modo que hacemos al identificar objetos reales, la abstracción nos ayuda a la hora de desarrollar una aplicación, permitiéndonos identificar los objetos que van a formar parte de nuestro programa, sin necesidad de disponer aún de su implementación; nos basta con reconocer los aspectos conceptuales que cada objeto debe resolver. Por ejemplo, cuando abordamos el desarrollo de un programa de gestión orientado a objetos, realizamos una abstracción de los objetos que necesitaríamos para resolver los procesos del programa: un objeto Empleado, para gestionar al personal de la empresa; un objeto Factura, para gestionar las ventas realizadas de productos; un objeto Usuario, para verificar las personas que utilizan la aplicación, etc.

Instancias de una clase

El proceso por el cuál se obtiene un objeto a partir de las especificaciones de una clase se conoce como instanciación de objetos. En la Figura 104 volvemos al ejemplo del molde y las figuras; en dicha imagen vemos un molde para fabricar figuras rectangulares, donde la clase Figura estaría representada por el molde, y cada uno de los objetos Figura (iguales en forma pero con la propiedad Color distinta), representaría una instancia de la clase.
Figura 104. Instanciación de objetos a partir de una clase.

Clases

Una clase no es otra cosa que el conjunto de especificaciones o normas que definen cómo va a ser creado un objeto de un tipo determinado; algo parecido a un manual de instrucciones conteniendo las indicaciones para crear el objeto. Los términos objeto y clase son utilizados en OOP con gran profusión y en contextos muy similares, por lo que para intentar aclarar en lo posible ambos conceptos, diremos que una clase constituye la representación abstracta de algo, mientras que un objeto constituye la representación concreta de lo que una clase define. 
La clase determina el conjunto de puntos clave que ha de cumplir un objeto para ser considerado perteneciente a dicha clase o categoría, ya que no es obligatorio que dos objetos creados a partir de la misma clase sean exactamente iguales, basta con que cumplan las especificaciones clave de la clase.Expongamos ahora las anteriores definiciones mediante un ejemplo preciso: un molde para crear figuras de cerámica y las figuras obtenidas a partir del molde. En este caso, el molde representaría la clase Figura, y cada una de las figuras creadas a partir del molde, sería un objeto Figura. Cada objeto Figura tendrá una serie de propiedades comunes: tamaño y peso iguales; y otras propiedades particulares: un color distinto para cada figura. 
Aunque objetos distintos de una misma clase pueden tener ciertas propiedades diferentes, deben tener el mismo comportamiento o métodos. Para explicar mejor esta circunstancia, tomemos el ejemplo de la clase Coche; podemos crear dos coches con diferentes características (color, tamaño, potencia, etc.), pero cuando aplicamos sobre ellos los métodos Arrancar, Acelerar o Frenar, ambos se comportan o responden de la misma manera.

Objetos

Un objeto es una agrupación de código, compuesta de propiedades y métodos, que pueden ser manipulados como una entidad independiente. Las propiedades definen los datos o información del objeto, permitiendo consultar o modificar su estado; mientras que los métodos son las rutinas que definen su comportamiento. Un objeto es una pieza que se ocupa de desempeñar un trabajo concreto dentro de una estructura organizativa de nivel superior, formada por múltiples objetos, cada uno de los cuales ejerce la tarea particular para la que ha sido diseñado.

Los fundamentos de la programación orientada a objeto

La organización de una aplicación en OOP se realiza mediante estructuras de código. Una estructura de código contiene un conjunto de procedimientos e información que ejecutan una serie de procesos destinados a resolver un grupo de tareas con un denominador común. 
Una aplicación orientada a objetos tendrá tantas estructuras de código como aspectos del programa sea necesario resolver. Un procedimiento que esté situado dentro de una de estructura de este tipo, no podrá llamar ni ser llamado por otro procedimiento situado en una estructura distinta, si no es bajo una serie de reglas. Lo mismo sucederá con los datos que contenga la estructura, permanecerán aislados del exterior, y sólo serán accesibles siguiendo ciertas normas. Una estructura de código, es lo que en OOP identificamos como objeto. 
Al ser las estructuras de código u objetos, entidades que contienen una información precisa y un comportamiento bien definido a través del conjunto de procedimientos que incluyen, pueden ser clasificados en función de las tareas que desempeñan. 
Precisamente, uno de los fines perseguidos por la OOP es conseguir una mejor catalogación del código, en base a estructuras jerárquicas dependientes, al estilo de un árbol genealógico. Trasladando las nociones que acabamos de exponer al ejemplo anterior, en el cual se programaban los procesos de gestión de los empleados de una empresa, el resultado obtenido será una estructura de código conteniendo todos los procedimientos, funciones y variables de la aplicación, implicados en las operaciones a realizar con un empleado, o lo que es lo mismo, un objeto Empleado. Entre los elementos de este objeto encontraremos el nombre, apellidos, alta del empleado, pago de nómina, etc. Todos los elementos que forman parte de un objeto componen la clase del objeto. Una clase consiste en el conjunto de especificaciones que permiten crear los objetos; en el caso expuesto por el ejemplo anterior sería la clase Empleado. 
Como acabamos de comprobar, las motivaciones que han llevado al desarrollo de la OOP son facilitar una mejor organización y clasificación del código, que la proporcionada por la programación procedural tradicional; aproximando al mismo tiempo, el modo de programar a la manera en que nuestra mente trabaja para aplicar soluciones a los problemas planteados.

Abordando un problema mediante programación procedural

Tomemos el ejemplo de un programador al que le encargan el desarrollo de una aplicación para la gestión de una empresa. Entre los diferentes cometidos a resolver, se encuentra el control de los empleados en lo que respecta a su alta, pago de sueldos, cálculo de vacaciones, etc.El programador se pone manos a la obra, desarrollando una aplicación basada en un enfoque procedural. Al llegar a los procesos relativos al empleado, va escribiendo las diferentes rutinas, distribuyéndolas a lo largo de los diferentes módulos que componen el programa. Ver el Código fuente 217.

Module General
Public psNombre As String
Public Sub Main()
' procedimiento de inicio del programa,
' aquí mostramos por ejemplo un menú
' para seleccionar alguno de los procesos
' del programa: altas de empleados,
' cálculo de nómina, periodos vacacionales, etc.
' ......
' ......
' ......
End Sub
Public Sub CalcularVacaciones(ByVal liIDEmpleado As Integer, _
ByVal ldtFechaInicio As Date, ByVal liNumDias As Integer)
' en este procedimiento calculamos
' el periodo de vacaciones del empleado
' pasado como parámetro
Dim ldtFechaFinal As Date
' ......
' obtener el nombre del empleado en función de su identificador
psNombre = "Juan"
psApellidos = "Plaza"
' ......
' ......
' calcular la fecha final y mostrar
' el periodo vacacional
ldtFechaFinal = DateAdd(DateInterval.Day, liNumDias, ldtFechaInicio)
Console.WriteLine("Empleado: {0} {1}", psNombre, psApellidos)
Console.WriteLine("Vacaciones desde {0} hasta {1}", _
Format(ldtFechaInicio, "dd/MMM/yy"), _
Format(ldtFechaFinal, "d/MMMM/yyyy"))
Console.ReadLine()
End Sub
' otros procedimientos del módulo
' ......
' ......
End Module
Module Varios
Public psApellidos As String
Public Sub CrearEmpleado(ByVal liIDEmpleado As Integer, _
ByVal lsNombre As String, ByVal lsApellidos As String, _
ByVal lsDNI As String, ByVal ldtFechaAlta As Date)
' grabamos los datos de un nuevo empleado en la
' base de datos que utiliza el programa
' ......
Console.WriteLine("Se ha grabado el empleado: {0} - {1} {2}", _
liIDEmpleado, lsNombre, lsApellidos)
Console.ReadLine()
End Sub
' otros procedimientos del módulo
' ......
' ......
End Module
Module Pagos
Public Sub TransfNomina(ByVal liIDEmpleado As Integer, ByVal ldbImporte As
Double)
' realizamos la transferencia de nómina
' a un empleado, utilizando su identificador
' ......
' obtenemos los datos del empleado
psNombre = "Ana"
psApellidos = "Roca"
' ......
' visualizamos el resultado
Console.WriteLine("Pago de nómina")
Console.WriteLine("Empleado: {0} {1}", psNombre, psApellidos)
Console.WriteLine("Ingresado: {0}", ldbImporte)
Console.ReadLine()
End Sub
Public Sub MostrarEmpleado(ByVal liIDEmpleado As Integer)
' buscar la información del empleado por su identificador
Dim lsDatosEmpleado As String
' ......
psNombre = "isabel"
psApellidos = "casillas"
lsDatosEmpleado = StrConv(psNombre & " " & psApellidos,
VbStrConv.ProperCase)
Console.WriteLine("El empleado seleccionado es: {0}", lsDatosEmpleado)
Console.ReadLine()
End Sub
' otros procedimientos del módulo
' ......
' ......
End Module
Código fuente 217
En el ejemplo anterior se declaran variables públicas en diferentes módulos del proyecto, y se crean procedimientos para las tareas relacionadas con el alta, visualización de datos, pagos, etc., del empleado. Todo este código se encuentra disperso a lo largo del programa, por lo que su mantenimiento, según crezca la aplicación, se hará progresivamente más difícil. Para solucionar este problema, necesitamos realizar un enfoque OOP de los procesos a desarrollar.

Del enfoque procedural al enfoque orientado a objeto

En la programación estructurada procedural, basada en procedimientos y funciones, el crecimiento de una aplicación hace que el mantenimiento de la misma se convierta en una tarea difícil, debido al gran número de procedimientos interrelacionados que podemos llegar a tener. El mero hecho de efectuar una pequeña modificación en un proceso, nos puede suponer el tener que recorrer un gran número de funciones del programa, no relacionadas por un nexo común.

Programación orientada a objeto (OOP)

Las ventajas de la programación orientada a objeto 

La programación orientada a objeto, OOP (Object Oriented Programming) a partir de ahora, se trata de una evolución de la programación procedural basada en funciones, que permite agrupar elementos de código (rutinas y datos) con funcionalidades similares, bajo un sistema unificado de manipulación y acceso a dichos elementos.

Ventana Desensamblador

Muestra el código que estamos depurando en formato desensamblado, es decir, las instrucciones a bajo nivel que componen cada una de las líneas de código de nuestro programa. Para acceder a esta ventana seleccionaremos el menú Depurar + Ventanas + Desensamblador. Ver Figura 103.
Figura 103. Ventana Desensamblador del depurador.

Ventana Resultados

Como acabamos de comprobar en el apartado anterior, cuando procedemos a ejecutar nuestro programa desde el IDE, se produce una carga de módulos en memoria. Esta ventana nos muestra información sobre dicho proceso de carga y su estado. Ver Figura 102.
Figura 102. Ventana Resultados del IDE. La opción de menú para esta ventana es Ver + Otras ventanas + Resultados.

Ventana Módulos

Visualiza los ensamblados o módulos cargados por el entorno de ejecución de la plataforma .NET Framework (ejecutables, librerías, etc.), necesarios para la ejecución del programa, junto a información adicional sobre su nombre, versión, orden de carga, etc. La opción de menú para abrir esta ventana es Depurar + Ventanas + Módulos. Ver Figura 101.
Figura 101. Ventana Módulos, del depurador.

Ventana Pila de llamadas - II

Entrando con el depurador en la ejecución de este código, cuando lleguemos al procedimiento Calcular( ), si abrimos la ventana Pila de llamadas nos ofrecerá un aspecto similar al de la Figura 100.


Figura 100. Ventana Pila de llamadas del depurador.

Ventana Pila de llamadas - I

Durante la ejecución de un programa, el procedimiento activo es situado en una lista que controla las llamadas entre procedimientos. Si dicho procedimiento llama a su vez a otro, el último llamado es agregado a la lista, pasando a ocupar el primer lugar y así sucesivamente. La ventana Pila de llamadas muestra esta lista de procedimientos apilados, de forma que el programador pueda comprobar la relación de llamadas efectuadas entre sí por los procedimientos en ejecución. La opción de menú para esta ventana es Depurar + Ventanas + Pila de llamadas. Tomemos como ejemplo el Código fuente 216, en el que desde un procedimiento Main( ) se hace una llamada al procedimiento VerFecha( ), y desde este al procedimiento Calcular( ).

Sub Main()
'....
VerFecha()
'....
End Sub
Public Sub VerFecha()
'....
Calcular()
'....
End Sub
Public Sub Calcular()
'....
End Sub
Código fuente 216

Ventanas adicionales en el IDE para la depuración

La opción de menú Depurar + Ventanas, contiene un numeroso conjunto de subopciones, que nos proporcionan acceso a diversas ventanas del IDE, relacionadas con aspectos de la depuración. En los siguientes apartados, vamos a realizar una descripción de las más importantes. 

Ventana Locales 

Esta ventana del depurador muestra el conjunto de identificadores de ámbito local al procedimiento que actualmente está siendo depurado, permitiéndonos además, la modificación de las variables a través de la propia ventana. La abriremos mediante la opción de menú Depurar + Ventanas + Locales. Ver Figura 98.
Figura 98. Ventana Locales del IDE, modificando el valor de una variable.

Inspecciones - II

Cuando al ejecutar este código desde el depurador nos encontremos dentro del bucle For, supongamos que nos interesa saber en todo momento el valor o resultado de los siguientes elementos: 
• Valor actual de la posición del array. 
• Resultado del cálculo en la expresión Dato 
* Valores(Indice) 
• Resultado de la expresión Dato >= Valores(Indice) Para obtener esta información, seleccionaremos la variable o expresión a controlar y haremos clic derecho, eligiendo del menú contextual la opción Agregar inspección. Esta operación creará una nueva inspección de código y la añadirá a una de las ventanas Inspección del IDE, que podemos abrir mediante la opción de menú Depurar + Ventanas + Inspección. Según vayamos ejecutando el código, las inspecciones definidas en esta ventana se irán actualizando. Ver Figura 96.
También podemos inspeccionar un elemento aún no definido como inspección, para ello lo seleccionaremos, y haciendo clic derecho sobre el mismo, elegiremos del menú contextual la opción Inspección rápida, que nos mostrará esta ventana con el valor a inspeccionar. Ver Figura 97.
Figura 97. Ventana Inspección rápida. 
Como puede observar el lector, esta inspección rápida inicialmente no forma parte del conjunto de inspecciones definidas en la ventana Inspección, pero podemos hacer que así sea, pulsando el botón Agregar inspección de la ventana.

Inspecciones - I

Una inspeccin consiste en un elemento de cdigo (identificador, expresin, etc.) que podemos seleccionar cuando nos encontramos en modo de depuracin, y sobre el que realizaremos una labor de supervisin durante la ejecucin del cdigo desde el depurador, para controlar los diferentes valores o estados que puede ir tomando durante el funcionamiento del programa. 
Tomemos como base para un ejemplo el Cdigo fuente 215.

Dim Valores() As Integer = {10, 20, 30, 40}
Dim Indice, Dato, Importe As Integer
Console.WriteLine("Introducir un valor")
Dato = Console.ReadLine()
For Indice = 0 To UBound(Valores)
Importe = Dato * Valores(Indice)
If Dato >= Valores(Indice) Then
Exit For
End If
Next
Cdigo fuente 215

La ventana Puntos de interrupcin

Esta ventana del IDE nos permite de un modo sencillo, la manipulacin de los puntos de interrupcin definidos en el proyecto. Ver Figura 95.
Figura 95. Ventana Puntos de interrupcin.
Como podemos observar, mediante esta ventana podemos realizar todas las operaciones posibles con los puntos de interrupcin, como definir nuevos, acceder a sus propiedades, eliminar, etc.

Eliminar

Podemos quitar un punto de interrupcin de varias formas: haciendo clic derecho sobre el punto, seleccionando la opcin Quitar punto de interrupcin del men contextual; pulsando [F9]; o haciendo clic en la marca del punto situada en el margen derecho del editor de cdigo. 
Podemos quitar todos los puntos establecidos seleccionando el men del IDE Depurar + Borrar todos los puntos de interrupcin.

Habilitar y deshabilitar

Durante el desarrollo del programa, puede que en ocasiones no estemos interesados en que un punto de interrupcin nos introduzca en el depurador, pero no queramos tampoco eliminarlo.Ante este tipo de situaciones, haremos clic derecho en el punto de interrupcin, y seleccionaremos del men contextual la opcin Deshabilitar punto de interrupcin, que lo dejar desactivado hasta que de igual modo seleccionemos la opcin de men Habilitar punto de interrupcin. La Figura 94 muestra el aspecto de un punto de interrupcin deshabilitado
Figura 94. Punto de interrupcin deshabilitado.
Para deshabilitar todos los puntos en un nico paso, emplearemos la opcin de men Depurar + Deshabilitar todos los puntos de interrupcin.

Punto de interrupcin a nivel de procedimiento - II

El punto de interrupcin en el editor de cdigo quedara en este caso como muestra la Figura 93. La entrada en el depurador por lo tanto, se producira en cuanto se comenzara a ejecutar el cdigo del procedimiento, siempre que lo permita la condicin y el recuento de visitas, en el caso de que estn establecidos.
Al definir puntos de interrupcin de esta manera hemos de ser cuidadosos, ya que si en el campo Funcin de su ventana de propiedades escribimos un valor que no corresponda a una rutina de cdigo, el IDE nos mostrar un error indicando que no puede crear el punto de interrupcin.

Punto de interrupcin a nivel de procedimiento - I

Existe otro modo de insertar un punto de interrupcin, no tan intuitivo como el que acabamos de describir, que consiste en utilizar la opcin de men Depurar + Nuevo punto de interrupcin. De esta forma, entramos directamente en la ventana de propiedades del punto de interrupcin, y en la pestaa Funcin, tenemos que escribir el nombre del procedimiento en el que estamos definiendo dicho punto. Suponiendo por ejemplo, que hemos escrito un procedimiento con el nombre VerFecha( ), y situados en cualquier lugar de su cdigo invocamos esta opcin, se mostrar la mencionada ventana de propiedades en la que escribiremos el nombre de esta rutina de cdigo. Ver Figura 92.
Figura 92. Definicin de un punto de interrupcin a nivel de procedimiento

Punto de interrupcin a nivel de procedimiento

Existe otro modo de insertar un punto de interrupcin, no tan intuitivo como el que acabamos de describir, que consiste en utilizar la opcin de men Depurar + Nuevo punto de interrupcin. De esta forma, entramos directamente en la ventana de propiedades del punto de interrupcin, y en la pestaa Funcin, tenemos que escribir el nombre del procedimiento en el que estamos definiendo dicho punto. Suponiendo por ejemplo, que hemos escrito un procedimiento con el nombre VerFecha( ), y situados en cualquier lugar de su cdigo invocamos esta opcin, se mostrar la mencionada ventana de propiedades en la que escribiremos el nombre de esta rutina de cdigo. Ver Figura 92.