índice del curso de VB .NET

Curso de iniciación a la programación
con Visual Basic .NET

Entrega número 16, (11/Jun/2004)
Publicada el 12/Jun/2004

 

Bueno, ya estamos nuevamente por aquí... Sí, ya se que soy un informal y que no cumplo lo que digo, al menos en lo relacionado a que cada mes iba a publicar una entrega... pero no es por no querer, si querer quiero, es más me gustaría publicar más de una entrega al mes, pero... pues eso, que no siempre podemos hacer lo que nos gustaría... así que... paciencia, paciencia, mucha paciencia...

Pues tal como te dije en la entrega anterior, en esta veremos cosas relacionadas con los espacios de nombres (Namespace), que de alguna forma está también está de alguna forma dentro del mismo tema de la visibilidad y ámbito, es decir desde dónde podemos acceder a los distintos elementos de nuestro programa y esas cosas.

¿Qué es un Namespace?

Introducción:

Empecemos recordando que es un espacio de nombres (Namespace):
Usando la definición de la primera entrega, te diré que un Namespace es una forma de agrupar clases (tipos) que están relacionadas de alguna forma.
El uso de los espacios de nombres nos permitirá tener nuestros ensamblados agrupados según la tarea para la que los hemos programado. De esta forma, si escribimos ensamblados que accederán al disco, los podemos agrupar para tenerlos en sitio diferente a los que, pro ejemplo, accedan a una base de datos. Eso mismo es lo que se hace en las clases base de .NET Framework y por esa razón existen los espacios de nombres System.IO y System.Data, por poner sólo dos.

Cada vez que creamos un proyecto con Visual Studio .NET de forma automática se crea un espacio de nombres para nuestra aplicación. Por tanto todos los tipos (clases, estructuras, enumeraciones, etc.) que definamos en dicho proyecto estarán incluidos dentro de ese espacio de nombres.
Aunque el editor de Visual Studio no nos muestra que todo esto es así, ya que para crear o definir un espacio de nombres debemos usar la instrucción Namespace y marcar el final de dicha definición usando End Namespace, por tanto es como si el IDE añadiera esas instrucciones por nosotros. Por eso, si has creado algún proyecto de C#, habrás visto que en ese lenguaje siempre se añade por defecto la definición del espacio de nombres, por tanto es importante saber que, aunque no lo veamos, todos nuestros proyectos estarán dentro de un espacio de nombres. Dicho Namespace se llamará de la misma forma que nuestro proyecto, salvo si tiene espacios, en ese caso se cambiarán los espacios (o caracteres no válidos en un nombre de .NET) por un guión bajo.

¿Dónde define el IDE de Visual Studio el espacio de nombres usado en nuestro proyecto?

El Visual Studio define el espacio de nombres "predeterminado" de nuestro proyecto en las propiedades del proyecto. Así que si quieres cambiar el Namespace predeterminado del proyecto, puedes hacerlo modificando dicho valor. Para poder hacer esto, muestra las propiedades del proyecto:
-Selecciona el proyecto en el explorador de soluciones (Solution Explorer)
-En el menú Proyecto, selecciona Propiedades
-En la ficha General (que será la que se muestre por defecto), el espacio de nombres estará en: Espacio de nombres de la raíz (Root namespace) tal como podemos ver en la figura 1.

 


Figura 1: El espacio de nombres predeterminado de un proyecto de VB .NET
 

 

En el caso de C#, también en la ventana de propiedades del proyecto de indica el Namespace predeterminado de dicho proyecto, pero además se añade al código el bloque namespace.
En la figura 2 podemos ver la ventana de propiedades de un proyecto de C#.

 


Figura 2: Las propiedades de un proyecto de C#
 

 

Quitar el Namespace predeterminado de un proyecto de VB .NET

Si queremos quitar ese espacio de nombres predeterminado, bien porque queramos usar otro diferente o bien, por que simplemente queremos quitarlo. Simplemente borraremos el nombre que se muestra en dicha ventana de propiedades.
A partir de ese momento, nuestro proyecto no tendrá ningún Namespace automático, si queremos usar uno, tendremos que definirlo nosotros mismos, pero por medio de código, usando un bloque Namespace / End Namespace e insertando todas las declaraciones de clases, etc., dentro de ese bloque.

 

¿Qué finalidad tiene el uso de los Namespace?

El escribir nuestro código dentro de un bloque Namespace tiene por finalidad, tal como te he comentado al principio, el poder mantener una especie de jerarquía. Para que nos entendamos mejor, podríamos comparar los espacios de nombres con los directorios de un disco. En cada directorio tendremos ficheros que de alguna forma están relacionados, de esta forma no mezclaremos los ficheros de música con los de imágenes ni con los proyectos de Visual Basic, por poner algunos ejemplos.
Pues lo mismo ocurre con las jerarquías creadas con los Namespace, de forma que podamos tener de alguna forma separados unos tipos de datos (clases, etc.) de otros.

 

Anidar espacios de nombres:
Espacios de nombres dentro de otros espacios de nombres

Siguiendo con el ejemplo de los directorios, es habitual que dentro de un directorio podamos tener otros directorios, de forma que tengamos ficheros que estando relacionados con el directorio principal no queremos que se mezclen con el resto de ficheros.
Pues con los Namespace ocurre lo mismo, podemos declarar bloques Namespace dentro de otro bloque existente. Esto se consigue definiendo un bloque dentro de otro bloque.
Por ejemplo:

Namespace CursoGuille
    Namespace Entrega16

        Module Module1
            Sub Main()

            End Sub
        End Module

    End Namespace
End Namespace

En este código, tenemos dos espacios de nombres anidados, el espacio de nombres Entrega16 está dentro del espacio de nombres CursoGuille.

 

¿Cómo acceder a los tipos declarados dentro de un Namespace?

De igual forma que para acceder a los ficheros de un directorio debemos indicar el "path" en el que se encuentran, con los espacios de nombres ocurre lo mismo, aunque como veremos (en breve, supongo) existen formas abreviadas de realizar ese acceso.
Por ejemplo, si queremos usar la clase StringBuilder que se encuentra declarada en el espacio de nombres System.Text, tendremos que indicar el espacio de nombres en el que se encuentra:

Dim sb As New System.Text.StringBuilder()

Es decir, debemos indicar el "path" completo de la clase, para poder acceder a ella.

En teoría si declaramos un método dentro del módulo Module1, (mostrado en el código anterior), deberíamos llamar a dicho método usando el espacio de nombres completo, pero cuando estamos dentro de un espacio de nombres, no hace falta indicar el nombre completo, ocurre lo mismo que cuando estamos dentro de en un directorio, no tenemos que indicar el path completo para acceder a un fichero de ese mismo directorio, pero si queremos también podemos hacerlo, tal como se muestra en el siguiente código:

Namespace CursoGuille
    Namespace Entrega16

        Module Module1
            Sub Main()
                CursoGuille.Entrega16.Module1.Prueba16()
            End Sub

            Public Sub Prueba16()
                Console.WriteLine("Saludos desde el Sub Prueba16")
            End Sub
        End Module

    End Namespace
End Namespace

 

Por tanto, para acceder a los miembros declarados dentro de un espacio de nombres, debemos usar la sintaxis: Espacio_de_nombres Punto Nombre_de_la_clase Punto Nombre_Del_Método
Si dicha clase está dentro de un espacio de nombres anidado, también debemos indicar dicho espacio de nombres.

Esto es tan habitual que seguramente ni te parecerá interesante, (al menos cuando pase algún tiempo y  estés algo más habituado a usarlos), ya que incluso para acceder a las propias clases de .NET usamos esta forma sintaxis, tal como se mostró antes para declarar la variable del tipo StringBuilder. En dicha declaración vimos que había dos espacios de nombres: System y dentro de éste está el espacio de nombres Text, el cual contiene la definición de la clase StringBuilder.

Es decir, siempre debemos indicar los espacios de nombres en los que se encuentran las clases, salvo que la clase (o tipo) esté definido en el mismo espacio de nombres desde el que se va a usar.

Aunque existen ciertas formas de hacer que esto no siempre tenga que ser así, ya que el código se puede convertir en algo más engorroso de leer si siempre tenemos que indicar los espacios de nombres que contienen las clases.

 

¿Cómo abreviar la escritura de nuestro código?
Para no tener que especificar siempre los espacios de nombres en los que están declaradas las clases.

Pues además de no tener que especificar los espacios de nombres cuando la clase (o tipo) está definido en el mismo en el que queremos usarla, (Guille, esto ya lo has dicho antes, ya lo se, pero así se enteran bien), podemos usar lo que se llama importaciones de espacios de nombres, de esa forma podemos acortar el código que tenemos que escribir.

Las importaciones de los espacios de nombres se hacen mediante la instrucción Imports (using en C#). Dicha instrucción se usará al principio del fichero de código y lo que realmente hace es indicarle al compilador que si no encuentra una clase en el espacio de nombres actual, la busque en el espacio de nombres que hemos importado.
Por ejemplo, la clase Console está definida en el espacio de nombres System, si usamos una importación de System en nuestro código (el Visual Studio lo hace de forma automática) no tendremos que indicar la "ruta" completa de dicha clase: System.Console, sino que podemos usarla indicando simplemente Console.

La instrucción Imports se usa de la siguiente forma:
Imports System

Si queremos importar un espacio de nombres que está "anidado" en otro, lo haremos así:
Imports System.Text

Es como si definiéramos un directorio dentro de la variable de entorno PATH, si queremos acceder a aun ejecutable que esté en cualquiera de esos directorios, no nos veremos obligados a indicarlo.

Por tanto el uso de Imports lo que hace es indicarle al compilador dónde buscar la definición de los tipos que estamos usando en nuestro código, para así ahorrarnos la escritura de los espacios de nombres que habitualmente usamos.

 

Las importaciones "automáticas" que hace Visual Studio

Como te he comentado, el Visual Studio hace una serie de importaciones de forma automática y dependerán del tipo de proyecto que estemos usando.
Para saber que espacios de nombres ha importado, podemos verlo en las propiedades del proyecto, particularmente en la opción "Importaciones", tal como podemos ver en la figura 3.

 


Figura 3: Las importaciones "automáticas" de un proyecto para consola
 

Esto quiere decir que podemos acceder a cualquiera de las clases de esos espacios de nombres sin necesidad de tener que indicarlos.
Estas importaciones serán efectivas (o válidas) en todos los ficheros que tengamos dentro del mismo proyecto, de esa forma si añadimos aquí algún espacio de nombres, dicho Namespace se usará en todo el proyecto.
Pero si queremos usarlo sólo en un fichero en concreto, podemos usar Imports, seguido del espacio de nombres, al principio de dicho fichero.

 

Nota:
Una cosa que no hay que confundir son las importaciones de espacios de nombres y las referencias.

Las referencias son las que le indican al compilador dónde encontrar las clases (y espacios de nombres) que queremos usar en nuestro proyecto, mientras que las importaciones simplemente hacen que no tengamos que escribir los espacios de nombres importados.
 

 

Por supuesto, las importaciones (Imports) las podemos realizar no sólo con los espacios de nombres definidos en .NET Framework, sino que podemos hacerlas para importar nuestros propios espacios de nombres.

Un detalle que es interesante, al menos en Visual Basic .NET, es que si hacemos una importación de un espacio de nombres, podemos acceder no sólo a las clases (tipos) definidos en ese espacio de nombres, sino también a otros espacios de nombres anidados.
Por ejemplo si queremos acceder a la clase StringBuilder que, como hemos visto, está definida en System.Text, es decir, en el espacio de nombres Text que a su vez está definido dentro de System, en Visual Basic podríamos hacerlo así:

Dim sb As New Text.StringBuilder()

Al menos si tenemos la importación del espacio System (que es el espacio de nombres raíz de .NET).

Nota:
En C# el código equivalente daría error, indicando que no se encuentra el espacio de nombres Text, es decir, en C# sólo se pueden usar los tipos definidos en un espacio de nombres importado (por medio de using), pero no se puede hacer referencia a los espacios de nombres anidados.

Una cosa que también deberías saber, es que las importaciones automáticas sólo son válidas si compilamos desde el propio Visual Studio, por tanto no serían efectivas si compilamos desde la línea de comandos. En ese caso, tendremos que indicar las importaciones usadas en cada uno de los ficheros o bien indicarlos usando el parámetro /imports: al llamar al compilador de Visual Basic .NET.

 

Para terminar con el tema de las importaciones de espacios de nombres, vamos a ver otra forma de usar la instrucción Imports, de forma que podamos "medio" importar un espacio de nombres.

 

Crear "alias" a los espacios de nombres

Un alias es una forma abreviada de usar algo. En el caso de las importaciones de espacios de nombres, podemos crear un alias para un espacio de nombres, de forma que en lugar de escribir todo el espacio de nombres (y subespacios) simplemente usemos ese alias.
Por ejemplo, imagina que quieres acceder a las clases del espacio de nombres System.IO pero no quieres realizar una importación completa, con idea de que al escribir dicho alias te muestre todas las clases y demás tipos relacionadas con ese espacio de nombres. En ese caso, podríamos crear un alias al espacio de nombres System.IO de esta forma:
Imports fic = System.IO

A partir de ese momento podemos acceder a los tipos definidos en dicho espacio de nombres usando el alias que hemos creado: fic.
Por ejemplo, si escribimos un punto después de fic, el IDE de Visual Studio nos mostrará las clases que podemos usar (las incluidas en ese espacio de nombres), tal como vemos en la figura 4.

 


Figura 4: Los tipos definidos en el "alias" de System.IO

 

Nota:
Los alias también se pueden usar en C#, (using fic = System.IO;), en los que puede ser incluso más prácticos que en VB, ya que en VB, por ejemplo no necesitaríamos crear un alias a System.IO, ya que podríamos usar directamente IO seguido de un punto para acceder a las clases que contiene.

 

Ejemplos de cómo usar los Namespace

Y ahora que hemos visto toda la "teoría" de los espacios de nombres (Namespace) vamos a verlo y aplicarlo de forma práctica (¡por fin!, ya creía que el Guille se iba a ir, pues he estado a punto de dar por terminada la entrega, así que no me toques las "narices", vayamos a liarla...).

En el ejemplo que vamos a usar, vamos a definir dos espacios de nombres y en cada uno de ellos declararemos algunas una clase, con idea de que veamos cómo usarlos desde cada uno de esos espacios de nombres.

El código sería el siguiente:

Namespace Entrega16
    Module Module1
        Sub Main()
            ' declarar una clase del espacio de nombres ClaseUno
            Dim c1 As New ClasesUno.PruebaA("Pepe", "Ruiz")
            '
            ' declarar una clase del espacio de nombres ClaseDos
            Dim c2 As New ClasesDos.PruebaB("Maria", "Sánchez")
            '
            Console.WriteLine("c1 = {0}", c1)
            Console.WriteLine("c2 = {0}", c2)
            '
            Console.ReadLine()
        End Sub
    End Module
End Namespace
'
Namespace ClasesUno
    Public Class PruebaA
        Private _nombre As String
        Private _apellidos As String
        '
        Public Sub New()
        End Sub
        Public Sub New(ByVal nombre As String, ByVal apellidos As String)
            Me.Nombre = nombre
            Me.Apellidos = apellidos
        End Sub
        '
        Public Property Nombre() As String
            Get
                Return _nombre
            End Get
            Set(ByVal value As String)
                _nombre = value
            End Set
        End Property
        Public Property Apellidos() As String
            Get
                Return _apellidos
            End Get
            Set(ByVal value As String)
                _apellidos = value
            End Set
        End Property
        '
        Public Overrides Function ToString() As String
            Return Apellidos & ", " & Nombre
        End Function
    End Class
End Namespace
'
Namespace ClasesDos
    Public Class PruebaB
        Inherits ClasesUno.PruebaA
        '
        Public Sub New()
        End Sub
        Public Sub New(ByVal nombre As String, ByVal apellidos As String)
            Me.Nombre = nombre
            Me.Apellidos = apellidos
        End Sub
    End Class
End Namespace

 

Es este código tenemos tres espacios de nombres:
-Entrega16 que es donde está declarado el módulo que se usará para iniciar la aplicación.
-ClasesUno en el que se define la clase PruebaA
-ClasesDos en el que se define la clase PruebaB, la cual simplemente hereda (o se basa en) la clase definida en ClasesUno.

Para poder acceder a las clases desde Main, tenemos que indicar en que espacio de nombres está cada una de las clases, esto es así porque el módulo que contiene el método Main está declarado dentro de un espacio  de nombres diferente.
Lo mismo ocurre con la instrucción Inherits ClasesUno.PruebaA de la clase PruebaB, ya que cada una de las clases está dentro de un espacio de nombres distinto y si no indicamos expresamente ese espacio de nombres, el compilador no sabrá donde localizar la clase PruebaA. Por supuesto, si hacemos una importación del espacio de nombres ClasesUno, podríamos acceder a la clase ClaseA sin necesidad de indicar el espacio de nombres que la contiene.

Un detalle, es que aunque estos tres espacios de nombres se incluyan en otro diferente, no es necesario tener que indicarlo, ni siquiera en C#.

 

Algunas cosas que debes saber sobre los Namespace "automáticos" y los definidos por tí

Para ir finalizando esta entrega quiero decirte que si quitas el espacio de nombres predeterminado que utiliza el Visual Studio y añades al código tu propios espacios de nombres, debo decirte que hay dos cosas que debes tener en cuenta:

Todo esto viene al caso porque en un mismo proyecto podemos definir varios espacios de nombres y si no somos precisos con la ubicación de cada tipo que tenemos en el proyecto, puede que el compilador se queje y nos diga que no encuentra tal o cual clase (o tipo).

También debes saber que si nuestro proyecto usa librerías creadas por nosotros, pero que simplemente las tenemos referenciadas, (es decir, podemos usar otras DLLs creadas por nosotros y ya compiladas), esos otros ensamblados (assemblies) pueden tener también un espacio de nombres que se llame igual que el que tenemos en nuestro proyecto, en ese caso no será necesario indicar el espacio de nombres de la otra librería, ya que podemos tener un mismo espacio de nombres "repartido" por varios ensamblados.
Esto es muy útil si queremos definir una serie de clases, enumeraciones, etc., en un proyecto, crear un ensamblado DLL a partir de ese proyecto y posteriormente usarlo en otro proyecto diferente, pero sin cambiar el espacio de nombres en el que tenemos definidos todos los tipos. Con la ventaja adicional de que esa DLL la podemos usar en proyectos de otros lenguajes de .NET, por tanto podemos crear con VB una librería de clases y usarla desde C#.

 

Resumiendo un poco:
En un proyecto (ensamblado) podemos definir varios espacios de nombres.
Un espacio de nombres puede estar definido en varios ensamblados y todas las clases (tipos) definidos se podrán acceder como si estuviesen en el mismo proyecto.
Podemos importar espacios de nombres para que el compilador sepa dónde buscar las clases.

 

Bueno, hasta aquí hemos llegado en esta primera entrega del año 2004, que espero que no sea la última, porque sino, a este paso tendremos que vivir varias vidas para poder enterarnos un poco de que va todo esto de la programación con Visual Basic .NET.

Aún se han quedado pendientes algunas de las cosas que te dije que iba a explicar en esta entrega, así que... a esperar a la entrega 17, que espero, pero no prometo, que será pronto.


Nos vemos.
Guillermo
Nerja, 11 y 12 de junio de 2004


ir a la entrega anterior ir al índice del curso vb.NET
 
ir al Glosario .NET
ir a la siguiente entrega (o al índice si esta es la última)

la Luna del Guille o... el Guille que está en la Luna... tanto monta...