30 mayo, 2007

Colecciones secuenciales de Objetos

Las colecciones Stack y Queue son dos tipos de colecciones que permiten el manejo de colecciones de datos secuenciales, veamos:

En el queue el primer elemento en entrar es el primero en salir (FIFO), veamos sus métodos

  • Enqueue = Agrega un elemento a la cola
  • Dequeue = Obtiene y elimina el siguiente método de la cola
  • Peek = Obtiene pero no elimina el siguiente método de la cola

Veamos un ejemplo:

Imports System.Collections

Module Module1

Sub Main()

Dim Cola As New Queue

Cola.Enqueue("Proceso_1")

Cola.Enqueue("Proceso_2")

Cola.Enqueue("Proceso_3")

Cola.Enqueue("Proceso_4")

Cola.Enqueue("Proceso_5")

While Cola.Count > 0

Console.WriteLine(Cola.Dequeue())

End While

Console.ReadKey()

End Sub

End Module

En el stack el último elemento en entrar es el primero en salir (LIFO), veamos sus métodos

  • Push = Agrega un elemento a la cola
  • Pop = Obtiene y elimina el siguiente método de la cola
  • Peek = Obtiene pero no elimina el siguiente método de la cola

Veamos un ejemplo:

Imports System.Collections

Module Module1

Sub Main()

Dim Pila As New Stack

Pila.Push("Proceso_1")

Pila.Push("Proceso_2")

Pila.Push("Proceso_3")

Pila.Push("Proceso_4")

Pila.Push("Proceso_5")

While Pila.Count > 0

Console.WriteLine(Pila.Pop())

End While

Console.ReadKey()

End Sub

End Module

Como podemos deducir de los ejemplos anteriores, el uso de ambas colecciones es bastante similar, la principal diferencia radica en el orden en el cual los elementos son extraídos.

26 mayo, 2007

Colecciones simples de Objetos

Vamos a conocer un poco sobre la colección más simple que nos proporciona el dot net Framework, el arraylist. Vemos los métodos más de mayor uso.

  • Add = Agrega un ítem a la colección
  • AddRange = Agrega una lista de ítems a la colección
  • Insert = Inserta un ítem en una lugar específico de la colección
  • InsertRange = inserta una lista de ítems en un lugar específico de la colección
  • Remove = Elimina un ítem de la colección
  • Remove at = Elimina un ítem de la colección basado en el índice del ítem
  • RemoveRange = Elimina una lista de ítems
  • Contains = Permite consultar si un ítem está contenido en la colección
  • Index of = Permite consultar el número del índice en el cual está contenido un ítem.
  • Clear = Elimina todos los ítem de la colección.

Antes de ver un ejemplo de cómo se usa todo esto, es importarte hacer referencia a que estas dos colecciones son colecciones de datos tipo object, por lo tanto, podríamos decir que son algo ineficientes desde el punto de vista de rendimiento, además, el compilador no nos ayuda mucho a prevenir errores de tipo de dato.

Imports System.Collections

Module Module1

Sub Main()

Dim datos As New ArrayList

For indice As Integer = 0 To 99

datos.Add(Rnd) 'Agrega un número aleatorio a la colección

Next

For indice As Integer = 99 To 0 Step -1

Console.WriteLine(datos(indice))

datos.RemoveAt(indice)

Next

Console.ReadKey()

End Sub

End Module

El recoger una colección de datos es muy tarea muy común y hay varias maneras de hacerlo, en el ejemplo anterior usamos un "For" pero el arraylist nos provee de la implementación del IEnumeration, esto nos permite recorrer la colección de una forma más fácil de entender y mantener, veamos:

Imports System.Collections

Module Module1

Sub Main()

Dim datos As New ArrayList

For indice As Integer = 0 To 99

datos.Add(Rnd) 'Agrega un número aleatorio a la colección

Next

Dim Navega_datos As IEnumerator = datos.GetEnumerator

Do While Navega_datos.MoveNext()

Console.WriteLine(Navega_datos.Current)

Loop

Navega_datos.Reset()

Console.ReadKey()

End Sub

End Module

Además de IEnumeration, contamos con la implementación de la interface ICollection, esta nos habilita el uso de lo siguiente:

  • Count = Retorna el número de elementos de la colección
  • Copyto = Copia el contenido de la colección en un arreglo

También es importante mencionar la interface Ilist que es la que le da la funcionalidad básica a la colección (add, addrange, clear, etc.)

24 mayo, 2007

Colecciones de datos

Todos los desarrolladores hemos tenido la necesidad de utilizar listas de datos, muchos solo hacen uso de los arreglos, sin embargo el dot net Framework nos proporciona una buena cantidad de listas especializadas, según el tipo de información que queramos manejar. Entonces el principal problema es determinar cuál es la lista más adecuada para el tipo de datos que queremos manejar. Conozcamos un poco las colecciones que encontramos en system.collections

Colección

Descripción

ArrayList

Almacena una lista de objetos

SortedList

Almacena una lista de objetos pero ordenados

Queue

Almacena una lista de objetos pero con la restricción de que el primer objeto en entrar es el primero en salir

Stack

Almacena una lista de objetos pero con la restricción de que el último objeto en entrar es el primero en salir

Hashtable

Almacena una colección de pares de valores, una llave y un valor.

SortedList

Almacena una colección de pares de valores, una llave y un valor, pero a diferencia de hashtable, los almacena de manera ordenada.

ListDiccionary

Tiene la misma funcionalidad del Hashtable, solo que optimizado para colecciones pequeñas (con pocos elementos)

HybridDiccionary

Esta colección se comporta como un ListDictionary cuando tiene pocos elementos, pero si la colección crece, toma el comportamiento del hashtable.

OrderedDictionary

Es muy similar al hashtable, pero agrega la funcionalidad necesaria para poder acceder a los elementos mediante un índice.

StringCollection

Es muy similar al ArrayList pero para manejar colecciones de string exclusivamente.

StringDiccionary

Es muy similar al Hashtable pero para manejar colecciones de string, tanto la llave como el valor tienen que ser string.

Las colecciones anteriormente citadas (a excepción de StringCollection y StringDiccionary) usan object como elementos, esto permite una gran confiabilidad pero no es lo mejor tomando en cuenta confiabilidad y el rendimiento. Cuando requiere de mejor rendimiento o mayor estabilidad de la aplicación (mediante la validación de tipos), el framework nos proporciona una serie de colecciones equivalentes a las anteriormente citadas, estas son llamadas colecciones genéricas (generic collection), y tienen la particularidad de comportarse igual que las anteriores pero con la particularidad que podemos definirle el tipo de dato que vamos a almacenar, ya no nos vemos obligados a usar el tipo "object".

El funcionamiento de estas colecciones es tan similar a las anteriormente vistas que existe una tabla de equivalencias, en la siguiente tabla podemos ver a la izquierda las colecciones que ya conocemos, pero cuando necesitemos trabajar con colecciones de un tipo de dato definido debemos usar el equivalente de la derecha, veamos:

Colección

Colección genérica

ArrayList

List

Queue

Queue

Stack

Stack

Hashtable

Dictionary

SortedList

SortedList

ListDictionary

Dictionary

HybridDictionary

Dictionary

OrderedDictionary

Dictionary

SortedDictionary

SortedDictionary

NameValueCollection

Dictionary

DictionaryEntry

KeyValuePair

StringCollection

List

StringDictionary

Dictionary

En futuros post espero poder mostrarles el funcionamiento de la mayoría de las colecciones.

22 mayo, 2007

Validando strings mediante patrones

En los sistemas de información la frase "Basura entra basura sale" es muy conocida, pero esta frase nunca nos debe servir para justificar las salidas incorrectas de un sistema, nos debe servir como experiencia que nos lleve a validar de mejor manera la información digitada por el usuario.

El Dot. Net Framework nos proporciona una serie de clases contenidas en el namespace system.text.regularexpressions que nos permiten validar la información del usuario mediante patrones conocidos como regular expression. Sinceramente debo indicar que la creación de estos patrones es bastante complicada y difícil de darle mantenimiento.

Para poder validar un string debemos primero crear un patrón, este patrón consta de una serie de caracteres que tienen un significado especial, veamos algunos de estos caracteres especiales y su significado.

Carácter

Uso

^

Inicio del string

$

Fin del string

\d{}

Solo dígitos numéricos, la cantidad la determina el número colocado entre {}

[ ]

Valida que el dígito sea igual a cualquiera de los caracteres contenidos entre las llaves

[ - ]

Valida que el dígito sea igual a cualquiera de los caracteres contenidos entre las llaves

*

Implica que repite el carácter precedente o puede no existir carácter

+

Implica que repite el carácter precedente estrictamente (debe de existir)

\s

Implica un espacio en blanco, puede ser espacio o tabulación

Veamos algunos ejemplos:

Para validar que se digite un teléfono válido, con el siguiente formato ###-#### podríamos usar el siguiente patrón:

Dato a Validar

Formato

Patrón

Número telefónico

###-####

^\d{3}-\d{4}$

Cédula (con guiones)

#-###-###

^[1-9]-\d{3}-\d{3}$

Correo Electrónico

nombre@dominio

^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)(([\w-]+\.)+))([a-zA-Z]{2,4}[0-9]{1,3})(\]?)$

Veamos un fragmento de código que nos aclare cómo utilizar regular expression

Imports System.Text.RegularExpressions

Module Module1

Sub Main()

Dim Mascara As String = ""

Dim PalabraaEvaluar As String = ""

While PalabraaEvaluar <> "Salir"

Console.Write("Máscara: ")

Mascara = Console.ReadLine()

Console.Write("Palabra: ")

PalabraaEvaluar = Console.ReadLine()

If Regex.IsMatch(PalabraaEvaluar, Mascara) Then

Console.WriteLine("Pasa la evaluación")

Else

Console.WriteLine("NO Pasa la evaluación")

End If

Console.ReadKey()

End While

End Sub

End Module

También podemos usar regular expressions para extraer fragmentos de un string, utilizando patrones similares a los anteriormente vistos

Imports System.Text.RegularExpressions

Module Module1

Sub Main()

Dim Completo As String = "Nombre: Alejandro Soto"

Dim Extracto As Match

Extracto = Regex.Match(Completo, "Nombre: (.*$)")

Console.WriteLine(Extracto.Groups(1))

Console.ReadKey()

End Sub

End Module

Hay libros completes sobre regular expression, el sentido de este post es solo hacer una breve reseña que sirva de introducción al tema.

19 mayo, 2007

Almacenamiento aislado (isolated storage)

En nuestros días se ha proliferado gran cantidad de malware (virus, spyware, adware, gusanos, troyanos, bots y otros). Estoy convencido que una de las causas de esta proliferación es la falta de seguridad en las aplicaciones que desarrollamos, prácticamente invitamos a los desarrolladores de malware a usar nuestra aplicaciones como entrada a las computadoras.

Cuando nuestra aplicación tiene que guardar archivos de configuración, preferencias o datos temporales, se nos presenta el problema de decidir donde guardarlo, ya que depende de donde lo guardemos nuestra aplicación dependerá de los privilegios del usuario que lo ejecute. Por eso creo que vale la pena escribir sobre la solución propuesta en el .Net Framework.

La Clase IsolatedStorageFile:

Esta clase nos provee de la funcionalidad necesaria para crear archivos y carpetas en las cuales nuestra aplicación pueda crear y accesar archivos en un almacenamiento seguro, aislado e independiente de los privilegios del usuario que ejecuta la aplicación. Tenemos dos tipos de almacenamiento:

Assembly/Machine: Permite crear un espacio de almacenamiento para la aplicación, independiente del usuario.

Assembly/User: Permite crear un espacio de almacenamiento independiente para el usuario.

Veamos cómo se usa:

Imports System.io

Imports system.IO.IsolatedStorage

Module Module1

Sub CreaArchivoenIsolated()

Dim EspacioenUsuario As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly()

'Creamos un directorio llamado Usuario1 (opcional)

EspacioenUsuario.CreateDirectory("Usuario1")

Dim ArchivoUsuario As IsolatedStorageFileStream = New IsolatedStorageFileStream("Usuario1\user.cfg", IO.FileMode.Create, EspacioenUsuario)

Dim UsuarioStream As StreamWriter = New StreamWriter(ArchivoUsuario)

'Se escribe en el archivo lo que necesitemos almacenar

UsuarioStream.WriteLine("Personalización del Usuario")

UsuarioStream.WriteLine("X = 10")

UsuarioStream.WriteLine("Y = 50")

UsuarioStream.Close()

ArchivoUsuario.Close()

EspacioenUsuario.Close()

End Sub

Sub EjemploDirectorio()

'Podemos listar los directorios creados en el Espacio de Usuario

Dim EspacioenUsuario As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly()

'Creamos otro directorio, solo para ejemplo.

EspacioenUsuario.CreateDirectory("Usuario2")

Dim Directorios() As String = EspacioenUsuario.GetDirectoryNames("*")

For Each directorio As String In Directorios

Console.WriteLine("Directorio encontrado: {0}", directorio)

Next

End Sub

Sub LeeArchivoenIsolated()

Dim EspacioenUsuario As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly()

Dim ArchivoUsuario As IsolatedStorageFileStream = New IsolatedStorageFileStream("Usuario1\user.cfg", IO.FileMode.Open, EspacioenUsuario)

Dim UsuarioStream As StreamReader = New StreamReader(ArchivoUsuario)

Console.WriteLine(UsuarioStream.ReadToEnd)

Console.ReadKey()

End Sub

Sub Main()

CreaArchivoenIsolated()

EjemploDirectorio()

LeeArchivoenIsolated()

End Sub

End Module

Consideraciones importantes

  1. En el isolatedstorage no podemos usar File.exists, por esto es necesario usar el GetFileNames("nombre_a_buscar") esto nos retorna un arreglo de string, en este debemos consultar por el length, si este es igual a 0 significa que el archivo consultado no existe.
  2. Para estar seguros que una clase puede accesar el isolatedstorage es necesario demandar el permiso anteponiendo la siguiente instrucción a nuestra clase <IsolatedStorageFilePermission(SecurityAction.Demand)>

16 mayo, 2007

Leyendo y escribiendo archivos comprimidos

En días anteriores escribí acerca de cómo leer y escribir archivos, hoy quiero ampliar este tema explicando cómo manejar archivos comprimidos.

Para crear y abrir archivos comprimidos el namespace system.io nos facilita dos clases Gzipstream y el Deflatestream. Estas clases implementan el mismo algoritmo de compresión, la principal diferencia radica en que el Gzip almacena información adicional en el encabezado, esto provoca que los archivos comprimidos con Gzip sean un poco más grandes que los comprimidos con Deflate, pero, esto le permite ser más compatible. Ambos algoritmos limitados a archivos inferiores a 4gb.

Si vamos a comprimir un archivo que vamos a enviar a otras máquinas es recomendable utilizar el Gzip y no el Deflate. Pero veamos un ejemplo de cómo usar la clase GzipStream

Imports system.io

Imports System.IO.Compression

Module Module1

Sub Main()

Dim NombreArchivoOrigen As String = "c:\temp\log.txt"

Dim NombreArchivoComprimido As String = "c:\temp\log.txt.gz"

Dim ArchivoOrigen As FileStream = File.Open(NombreArchivoOrigen, FileMode.Open, FileAccess.Read)

Dim ArchivoDestino As FileStream = File.Open(NombreArchivoComprimido, FileMode.CreateNew, FileAccess.Write)

Dim MiStream As New GZipStream(ArchivoDestino, CompressionMode.Compress)

'Se utiliza integer en lugar de byte para poder almacenar -1.

Dim Mibyte As Integer = ArchivoOrigen.ReadByte()

While Mibyte <> -1

MiStream.WriteByte(CType(Mibyte, Byte))

Mibyte = ArchivoOrigen.ReadByte()

End While

MiStream.Close()

ArchivoOrigen.Close()

ArchivoDestino.Close()

Dim infoarchivoorigen As FileInfo = New FileInfo(NombreArchivoOrigen)

Dim infoarchivocomprimido As FileInfo = New FileInfo(NombreArchivoComprimido)

Console.WriteLine("Tamaño original : {0}", infoarchivoorigen.Length)

Console.WriteLine("Tamaño comprimido: {0}", infoarchivocomprimido.Length)

Console.ReadKey()

End Sub

End Module

Ahora, que si no queremos usar el Gzip sino el deflate solo requerimos de cambiar la clase GzipStream por DeflateStream el resto del procedimiento es igual, veamos:

Imports system.io

Imports System.IO.Compression

Module Module1

Sub Main()

Dim NombreArchivoOrigen As String = "c:\temp\log.txt"

Dim NombreArchivoComprimido As String = "c:\temp\log.txt.gz"

Dim ArchivoOrigen As FileStream = File.Open(NombreArchivoOrigen, FileMode.Open, FileAccess.Read)

Dim ArchivoDestino As FileStream = File.Open(NombreArchivoComprimido, FileMode.CreateNew, FileAccess.Write)

Dim MiStream As New DeflateStream(ArchivoDestino, CompressionMode.Compress)

'Se utiliza integer en lugar de byte para poder almacenar -1.

Dim Mibyte As Integer = ArchivoOrigen.ReadByte()

While Mibyte <> -1

MiStream.WriteByte(CType(Mibyte, Byte))

Mibyte = ArchivoOrigen.ReadByte()

End While

MiStream.Close()

ArchivoOrigen.Close()

ArchivoDestino.Close()

Dim infoarchivoorigen As FileInfo = New FileInfo(NombreArchivoOrigen)

Dim infoarchivocomprimido As FileInfo = New FileInfo(NombreArchivoComprimido)

Console.WriteLine("Tamaño original : {0}", infoarchivoorigen.Length)

Console.WriteLine("Tamaño comprimido: {0}", infoarchivocomprimido.Length)

Console.ReadKey()

End Sub

End Module

Ahora que ya sabemos cómo comprimir, debemos aprender a descomprimir, la lógica es la misma, solo debemos invertirla. Veamos:

Imports system.IO

Imports System.IO.Compression

Module Module1

Sub Main()

Dim NombreArchivoComprimido As String = "c:\temp\log.txt.gz"

Dim NombreArchivoDestino As String = "c:\temp\log.txt"

Dim ArchivoOrigen As FileStream = File.Open(NombreArchivoComprimido, FileMode.Open, FileAccess.Read)

Dim ArchivoDestino As FileStream = File.Open(NombreArchivoDestino, FileMode.CreateNew, FileAccess.Write)

Dim MiStream As New GZipStream(ArchivoOrigen, CompressionMode.Decompress)

Dim Mibyte As Integer = MiStream.ReadByte()

While Mibyte <> -1

ArchivoDestino.WriteByte(CType(Mibyte, Byte))

Mibyte = MiStream.ReadByte()

End While

MiStream.Close()

ArchivoOrigen.Close()

ArchivoDestino.Close()

Dim infoarchivoorigen As FileInfo = New FileInfo(NombreArchivoComprimido)

Dim infoarchivodestino As FileInfo = New FileInfo(NombreArchivoDestino)

Console.WriteLine("Tamaño comprimido : {0}", infoarchivoorigen.Length)

Console.WriteLine("Tamaño destino : {0}", infoarchivodestino.Length)

Console.ReadKey()

End Sub

End Module

El anterior ejemplo descomprime utilizando GZip si el archivo que deseamos descomprimir fue comprimido mediante Deflate solo tenemos que cambiar la clase y listo, el resto es exactamente igual.

14 mayo, 2007

Leyendo y escribiendo archivos

Stream

Esta clase nos brinda una serie de métodos para trabajar con datos secuenciales, además, se especializa según los datos con los cuales vamos a trabajar en:

FileStream

MemoryStream

CriptoStream

NetworkStream

GZipStream

Empecemos con el primero, el FileStream. Como su nombre lo indica permite hacer operaciones sobre los datos contenidos en los archivos. Lo primero que necesitamos conocer es como obtener el FileStream de un archivo, esto lo hacemos mediante la clase File:

Dim Miarchivo As FileStream = File.Open("c:\prueba.log", FileMode.Open, FileAccess.Read)

Sin embargo, para facilitar la lectura del archivo podemos utilizar el StreamReader ya que el FileStream lee el archivo como un arreglo de bytes, el StreamReader permite leer el archivo como un simple string. Veamos cómo podemos hacer esto:

Sub Main()

Dim Miarchivo As FileStream = File.Open("c:\prueba.log", FileMode.Open, FileAccess.Read)

Dim Mistreamreader As New StreamReader(Miarchivo)

Console.WriteLine(Mistreamreader.ReadToEnd())

Console.ReadKey()

End Sub

Mediante el OpenText de la clase File podemos simplificar el código anterior:

Sub Main()

Dim Mistreamreader As StreamReader = File.OpenText("c:\prueba.log")

Console.WriteLine(Mistreamreader.ReadToEnd())

Console.ReadKey()

End Sub

De igual forma podemos crear un nuevo archivo:

Sub Main()

Dim Mistreamwriter As StreamWriter = File.CreateText("c:\temp\prueba.log")

Mistreamwriter.WriteLine("Primera linea")

Mistreamwriter.WriteLine("Segunda linea")

Mistreamwriter.Close()

End Sub

Es importante tomar en cuenta que el fragmento de código anterior sobre escribe el archivo.

En algunas ocasiones es necesario crear el stream en memoria de manera temporal, antes de almacenarlo, por ejemplo, en un archivo. Para estos casos se puede utilizar el memorystream, su uso es muy similar al filestream. Veamos un ejemplo:

Sub Main()

Dim Mitemp As New MemoryStream()

Dim Mistream As StreamWriter = New StreamWriter(Mitemp)

Mistream.WriteLine("Primera Linea")

Mistream.WriteLine("Segunda Linea")

Mistream.WriteLine("Tercera Linea")

Mistream.Flush()

Dim Miarchivo As FileStream = File.Create("c:\temp\prueba.txt")

Mitemp.WriteTo(Miarchivo)

Mitemp.Close()

Mistream.Close()

Miarchivo.Close()

End Sub

Cuando necesitamos manejar stream que requieran gran velocidad contamos con el streambuffered, su uso es muy similar a los anteriores por lo cual solo lo voy a citar, en futuros artículos voy a comentar sobre los otros tipos de blogs.

10 mayo, 2007

Manejo de archivos, carpetas y unidades mediante system.io

Una de las actividades comunes al desarrollar es tratar con archivos, por eso quiero escribir un poco de las facilidades que .net Framework nos proporciona.

Lo primero que debemos conocer es el namespace system.io, el cual nos proporciona una serie de clases para el manejo de archivos, carpetas y hasta unidades completas.

Podríamos decir que system.io se divide en dos tipos de clases, las de información (derivadas de filesysteminfo) y las de utilidades (file, directory y path)

Pero, veamos como se utilizan, empecemos con FileInfo, este nos permite ver información de un archivo.

Imports System.IO

Module Module1 Sub Main()

Dim Mi_archivo As New FileInfo("c:\windows\explorer.exe")

Console.WriteLine("Directorio = {0}", Mi_archivo.DirectoryName)

Console.WriteLine("Nombre = {0}", Mi_archivo.Name)

Console.WriteLine("Extensión = {0}", Mi_archivo.Extension)

Console.WriteLine("Fecha de creación = {0}", Mi_archivo.CreationTimeUtc)

Console.WriteLine("Fecha última modificación = {0}",

Mi_archivo.LastWriteTimeUtc)

Console.ReadKey()

End Sub

End Module

Pero, el fileinfo además de brindarnos información de un archivo nos permite realizar algunas operaciones con él.

Mi_archivo.CopyTo("c:\winres\explorer.res", True)

Mi_archivo.MoveTo("c:\carpeta\respaldo.bak")

Otras clases importantes son las siguientes

Directory_info

Permite manipular directorios

DriveInfo

Permite manipular unidades de disco (isReady, TotalSize, TotalFreeSpace)

Path

Permite manejar rutas de archivos de forma más eficiente que si las manejáramos como simples cadenas de texto

FileSystemWatcher

Permite monitorear cambios (Creación, modificación, renombrado, borrado) el sistema de archivos y directorios.

En el siguiente ejemplo podemos ver como listar los archivos de una carpeta específica.

Sub Main()

Dim Mi_directorio As DirectoryInfo = New DirectoryInfo("c:\windows")

For Each Mi_archivo As FileInfo In Mi_directorio.GetFiles()

Console.WriteLine("Archivo: {0}, Tamaño: {1} bytes", Mi_archivo.Name, Mi_archivo.Length)

Next

Console.ReadKey()

End Sub

07 mayo, 2007

Interfaces

Cuando empecé a explorar las posibilidades que nos brindan las interfaces, se me complicó entender su utilidad, por eso quiere dedicar este espacio a escribir sobre interfaces (en .net Framework por supuesto)

¿Qué es una interface?

Usualmente la interface es como un contrato. Este contrato lo que tiene es una lista de propiedades, funciones, métodos y eventos incluso clases, estructuras o interfaces anidadas. Cualquier clase que desee implementar una interface debe por obligación de proveer todos los miembros listados en la interface.

Características:

  • La interface no contiene lógica de programación
  • Minimizan los problemas de compatibilidad
  • Facilita el desarrollo, cuando se trabajan con grupos de desarrolladores.
  • El .Net Framework utiliza interfaces

Ejemplo 1:

La forma más sencilla de entender este concepto es mediante un ejemplo, veamos la siguiente interface

Interface IfiguraGeometrica

Function Area() As Int32

Function Perimetro() As Int32

Property Color() As colores

Enum colores

Rojo

Verde

Azul

End Enum

End Interface

Esta interface define que toda clase que la tenga que implementar debe desarrollar dos funciones Área y Perímetro además de la propiedad color. Esto nos permite implementar el siguiente código:

Sub Despliega_area(ByVal _figura As IfiguraGeometrica)

Console.WriteLine("Área de la figura = {0}", _figura.Area)

Console.ReadKey()

End Sub

El código anterior despliega en la consola el área de una figura geométrica, lo interesante es que aún no hemos implementado las clases correspondientes a las figuras geométricas, de hecho podría ser que no conozcamos todas las figuras geométricas, pero mientras implementen la interface nuestro código funcionará sin problemas. Veamos la implementación de la interface en una clase "Cuadrado":

Class Cuadrado

Implements IfiguraGeometrica

Private i_lado As Integer Private _color As IfiguraGeometrica.colores

Public Function Area() As Integer Implements IfiguraGeometrica.Area

Return i_lado * i_lado

End Function

Public Property Color() As IfiguraGeometrica.colores

Implements IfiguraGeometrica.Color

Get

Return _color

End Get

Set(ByVal value As IfiguraGeometrica.colores)

_color = value

End Set

End Property Public Function Perimetro() As Integer

Implements IfiguraGeometrica.Perimetro

Return i_lado * 4

End Function

Public Property Lado() As Integer

Get

Return i_lado

End Get

Set(ByVal value As Integer)

i_lado = value

End Set

End Property

End Class

Interfaces del .Net Framework

Como comenté anteriormente el .Net Framework utiliza una serie de interfaces que facilitan que nuestras propias clases puedan hacer uso de algunas funciones ya implementadas, las más comunes son las siguientes:

  • IComparable (Utilizada cuando se requiere ordenar )
  • IDisposable (Cuando se necesitan liberar recursos manualmente)
  • IConvertible (Cuando se necesita convertir la implementación a una clase base)
  • ICloneable (Cuando se requiere clonar el objeto)
  • IEquatable (Habilita la comparación entre dos instancias)
  • IFormattable (Permite convertir el valor del objeto en un string con un formato específico)

05 mayo, 2007

Tipos de Datos

En los siguientes días voy a estar escribiendo algunas entradas al blog sobre el .Net Framework. Me parece importante empezar escribiendo sobre cómo se clasifican los tipos de datos según la forma en la cual se almacenan en la memoria. Esta clasificación es la siguiente:

  • Tipos por Valor
  • Tipos por Referencia

Tipos por Valor.

Los tipos por valor son todos aquellos tipos que almacenan directamente su valor en el espacio de memoria de la variable.

Entre ellas tenemos:

  • Build-in (Son los tipos base provistos por el Framework.)
  • Enumeraciones
  • Estructuras

Características:

  • Se guardan en el espacio de memoria llamado stack
  • Derivan de system.valuetype
  • Almacenan 16 bytes o menos
  • Tienen un excelente performance

Consideraciones importantes:

  • Al pasar un tipo por valor en un argumento de un procedimiento se crea una copia del tipo por valor, por lo tanto no se modifica el valor de la variable original
  • El runtime está optimizado para el uso del int32 y el double para operaciones de punto flotante.

Tipos por Referencia.

Los tipos por referencia son todos aquellos tipos que en vez de almacenar el valor directamente, almacenan una dirección del heap, que es donde se almacena el contenido de la variable, podríamos decir que son punteros.

Características:

  • Todo tipo que no derive de system.valuetype es un tipo por referencia
  • La mayoría de los tipos son por referencia.
  • Su contenido se guarda en el heap
  • El Garbage Collection se encarga de eliminar el contenido de los ítems que ya no son referenciados
  • Al asignar una variable a otra variable, no se copia el valor, lo que se copia es la dirección de memoria.

Consideraciones Importantes:

El string es uno de los principales tipos por referencia. En .NET el string es inmutable, por lo cual cada vez que un string cambia, el runtime crea un nuevo string y abandona la dirección anterior, esto tiene un costo en el rendimiento. Para ser más eficientes en el manejo de string (cuando estos deben cambiar) se recomienda el uso del stringbuilder.