Implementando un interfaz para crear una nueva colección

Implementando un interfaz para crear una nueva colección

Como acabamos de comprobar en el ejemplo anterior, la creación de nuevas clases de tipo collection mediante herencia es una estupenda solución. Debido a que el código principal ya existe en la clase base, simplemente tenemos que añadir el código para el nuevo comportamiento en la clase derivada, mediante la creación de nuevos miembros, a través de sobrecarga, o sobre-escritura. Sin embargo, esta técnica tiene el inconveniente de que no podemos modificar o eliminar ciertos comportamientos de la clase base.

Para salvar este obstáculo, en lugar de heredar de una colección, podemos emplear otra técnica, que consiste en crear una clase, e implementar en ella uno o varios interfaces de los incluidos en el espacio

de nombres System.Collections, los cuales definen las características que deben tener los arrays y colecciones del entorno.

La ventaja de implementar interfaces de colección en una clase, reside en que tenemos control absoluto en cuanto al comportamiento que tendrán los objetos collection que instanciemos de dicha clase. Aunque como inconveniente, tenemos el hecho de que la implementación de un interfaz, obliga

a codificar todos los miembros que vienen en la declaración de dicho interfaz; respecto a esto último, podemos escribir sólo la declaración de algunos miembros y no su código; de esta manera, para aquellos aspectos del interfaz en los que no estemos interesados, no será necesario codificar.

Supongamos como ejemplo, que necesitamos en nuestro programa una colección que convierta a mayúsculas los valores que añadimos o modificamos. Para ello, vamos a crear una clase con el nombre ListaMay, que implemente el interfaz IList. Este interfaz está compuesto por un numeroso conjunto de miembros, pero nosotros sólo vamos a codificar los siguientes.

• Add( ). Añadir un nuevo elemento. • Item( ). Asigna u obtiene un valor. • Contains( ). Comprueba si existe un valor entre los elementos de la colección, devolviendo un

valor lógico Verdadero si existe, o Falso en el caso de que no exista. • Count. Devuelve el número de elementos que hay en la colección. • GetEnumerator( ). Devuelve un enumerador para recorrer el array de la colección. • Clear( ). Elimina los valores de los elementos del array que tiene la colección.

Para el resto de miembros del interfaz, aunque no vayamos a utilizarlos, debemos crear su declaración vacía, ya que en caso contrario, se producirá un error al intentar ejecutar el programa, porque el entorno detectará la falta de la creación de los miembros de dicho interfaz en nuestra clase.

No codificamos todos los miembros del interfaz para simplificar el presente ejemplo, y al mismo tiempo, demostramos que sólo hemos de escribir código para aquellos aspectos del interfaz que necesitemos, aunque lo recomendable sería, evidentemente, implementar correctamente todos los métodos y propiedades que indica el interfaz. Veámoslo en el Código fuente 388.

' esta clase implementa la funcionalidad de una colección; ' admite como elementos cadenas de caracteres, ' y los convierte a mayúsculas

Programación con Visual Basic .NET © Grupo EIDOS

Class ListaMay ' para conseguir el comportamiento de una colección ' en esta clase implementamos el siguiente interfaz Implements IList

' declaramos un array que contendrá ' los valores de la colección Protected aValores() As String

' a partir de aquí, debemos declarar todos los miembros ' del interfaz, y codificar aquellos que necesitemos ' ----------------------------------------------------- Public ReadOnly Property Count() As Integer _

Implements System.Collections.IList.Count

Get If Not (aValores Is Nothing) Then Count = aValores.Length End If End Get

End Property

Public ReadOnly Property IsSynchronized() As Boolean _ Implements System.Collections.IList.IsSynchronized

Get End Get

End Property

Public ReadOnly Property SyncRoot() As Object _ Implements System.Collections.IList.SyncRoot

Get End Get

End Property

Public Function GetEnumerator() As System.Collections.IEnumerator _ Implements System.Collections.IList.GetEnumerator

Return aValores.GetEnumerator()

End Function

Public Function Add(ByVal value As Object) As Integer _ Implements System.Collections.IList.Add

If aValores Is Nothing Then ReDim Preserve aValores(0) aValores(0) = CStr(value).ToUpper()

Else Dim iIndiceMayor As Integer = aValores.GetUpperBound(0) ReDim Preserve aValores(iIndiceMayor + 1) aValores(iIndiceMayor + 1) = CStr(value).ToUpper()

End If

Return Me.Count End Function

Public Sub Clear() _ Implements System.Collections.IList.Clear

Array.Clear(aValores, 0, aValores.Length)

End Sub

© Grupo EIDOS 25. Colecciones personalizadas

Public Function Contains(ByVal value As Object) As Boolean _ Implements System.Collections.IList.Contains

Dim oEnumera As IEnumerator oEnumera = aValores.GetEnumerator() While oEnumera.MoveNext

If (oEnumera.Current = CType(value, String).ToUpper()) Then Return True End If End While

Return False

End Function

Public Function IndexOf(ByVal value As Object) As Integer _ Implements System.Collections.IList.IndexOf

End Function

Public ReadOnly Property IsFixedSize() As Boolean _ Implements System.Collections.IList.IsFixedSize

Get End Get

End Property

Public ReadOnly Property IsReadOnly() As Boolean _ Implements System.Collections.IList.IsReadOnly

Get End Get

End Property

Default Public Property Item(ByVal index As Integer) As Object _ Implements System.Collections.IList.Item

Get Item = aValores.GetValue(index) End Get Set(ByVal Value As Object)

Dim oTipo As Type oTipo = Value.GetType()

If oTipo.Name = "String" Then

aValores.SetValue(CType(Value, String).ToUpper(), index) Else aValores.SetValue(Value, index) End If End Set

End Property

Public Sub Remove(ByVal value As Object) _ Implements System.Collections.IList.Remove

End Sub

Public Sub RemoveAt(ByVal index As Integer) _ Implements System.Collections.IList.RemoveAt

End Sub

Public Sub Insert(ByVal index As Integer, ByVal value As Object) _

Programación con Visual Basic .NET © Grupo EIDOS

Implements System.Collections.IList.Insert

End Sub

Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) _ Implements System.Collections.IList.CopyTo

End Sub

End Class

Código fuente 388

Desde código cliente, el modo de utilizar nuestra nueva clase es igual que para una de las colecciones normales, aunque debemos tener en cuenta los métodos no codificados, para no utilizarlos. Veamos el Código fuente 389.

Public Sub Main() ' instanciar un objeto de la colección personalizada Dim oLis As ListaMay = New ListaMay()

Console.WriteLine("Número de elementos {0}", oLis.Count) Console.WriteLine()

' añadir valores oLis.Add("Esta es") oLis.Add("mi clase") oLis.Add("de arrays personalizados") RecorrerMiLista(oLis)

Console.WriteLine("Número de elementos {0}", oLis.Count) Console.WriteLine()

' comprobar si existe un valor Dim sValorBuscar As String Console.WriteLine("Introducir un valor a buscar en la colección") sValorBuscar = Console.ReadLine() If oLis.Contains(sValorBuscar) Then

Console.WriteLine("El valor introducido sí existe") Else Console.WriteLine("El valor introducido no existe") End If Console.WriteLine()

' eliminar valores de la colección (no elimina elementos) oLis.Clear()

' asignar valores a los índices existentes de la colección oLis(2) = "mesa" oLis.Item(0) = "coche"

RecorrerMiLista(oLis)

Console.ReadLine() End Sub

Public Sub RecorrerMiLista(ByVal oListaValores As ListaMay) Dim oEnumera As IEnumerator oEnumera = oListaValores.GetEnumerator() While oEnumera.MoveNext

Console.WriteLine("valor {0}", oEnumera.Current) End While

© Grupo EIDOS 25. Colecciones personalizadas

Console.WriteLine() End Sub

Código fuente 389.

Manipulación de errores