domingo, 27 de agosto de 2017

Interfaces ICollection y IList en C# - Parte 2/2

Índice

1. Introducción
2. Palabras Clave
3. Generalidades
4. Interfaz IList
5. Interfaz Genérica IList<T>
6. Interfaz IReadOnlyList<T>
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Esta segunda entrega de Interfaces ICollection y IList en C# describe dos interfaces de colecciones: IList y IList<T>. Además, se estudiará la interfaz para tipos genéricos IReadOnlyList<T>; una interfaz para la implementación de colecciones de sólo lectura. Antes de empezar, es necesario dejar evidente que estas interfaces están orientadas a colecciones que acceden a sus elementos a través de un índice.

2. Palabras Clave

  • Colección
  • Índice
  • Lista
  • Protocolo

3. Generalidades

Las interfaces IList (no genérica) y IList<T> (genérica) están orientadas para colecciones de elementos que requieren acceder o modificar su contenido por medio de un índice.

Este tipo de colecciones sigue, de forma análoga, el modelo de los arreglos: el acceso a los elementos se reaiza por medio de un índice; tal como se muestra en la siguiente imagen:
Modelo de acceso a elementos por índice
Figura 1. Modelo de acceso a elementos por índice ("Learning the Concept of Arrays", 2017).

4. Interfaz IList

IList ("IList Interface", 2017) es la versión no-genérica de una estructura de datos o colección en la que se accede a los elementos a través de un índice.


Entre las características paticulares de esta interfaz, está la de definir estructuras (Ídem):
  • Sólo lectura: la lista no puede ser modificada.
  • Tamaño fijo: las operaciones de agregación o remoción no están permitidas, sin embargo los elementos existentes puede ser modificados.
  • Tamaño variable: todas las operaciones están permitidas: agregación, remoción y modificación.
Las funciones -propiedades y métodos-, que deben ser implementados desde interfaces son los que se enlistan aquí (Albahari, 2012):

public interface IList : ICollection, IEnumerable
{
    object this [int index] {get; set}
    bool IsFixedSize { get; }
    bool IsReadOnly { get; }
    int Add (object value);
    void Clear();
    bool Contains (object value);
    int IndexOf (object value);
    void Insert (int index, object value);
    void Remove (object value);
    void RemoveAt (int index);
}

4. Interfaz Genérica IList<T>

La interfaz o protocolo IList<T> es la versión genérica de una colección donde los elementos se acceden por su índice ("IList(T) Interface", 2017). Hereda los métodos de las interfaces genéricas ICollection<T> ("Interfaces ICollection y IList", 2017) y IEnumerable<T> ("Enumeración e Interfaces IEnumerator(T) e IEnumerable(T)", 2017) para ser implementados en clases concretas.

Los métodos abstractos propios de esta interfaz (Albahari, 2017):

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    T this [int index] { get; set; }
    int IndexOf (T item);
    void Insert (int index, T item);
    void RemoveAt (int index);
}

Para conocer más detalles técnicos acerca de esta interfaz consultar la documentación oficial: IList Interface (System.Collections).

Vale destacar que el método Add (heredado de ICollection<T>) de IList<T> no retorna un entero sino void. Esta diferencia es importante considerarla a la hora de hacer implementaciones concretas, dado qe podría conducir a confusiones.

5. Interfaz IReadOnlyList<T>

IReadOnlyList<T> ("IReadOnlyList(T) Interface", 2017) es una interfaz que representa una colección basada en índices para acceder a sus elementos, pero que sólo permite la lectura, orden y número de elemenos fijos; las demás operaciones no están permitidas: agregación o remoción.

Como se advierte en Albahari (2012), esta interfaz se introduce para permitir la interoperabilidad de Windows Runtime (C# y Windows Runtime). Su introducción se lleva a cabo sobre la versión 4.5 de .NET Framework.

De acuerdo con su especificación: 

public interface IReadOnlyList<out T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }
    T this[int index] { get; }
}

es importante distinguir que cuenta sólo los miembros necesarios para respetar las condiciones de formación de sólo lectura: conteo de elementos y acceso a los elementos por índice. En vista de lo anterior, se puede decir IReadOnlyList<T> es una versión básica de IList<T>.

Es necesario, además, mencionar respecto a la especificiación de código anterior, que el tipo paramétrico T está marcado como covariante; es decir sólo se permite el retorno de elementos de un tipo concreto; el retorno de valores del tipo paramétrico no está habilitado en este modo de especificación ("out (generic modifier)", 2017): bajo está modalidad no es posible especificar T como tipo de parámetros en métodos o propiedades. 

6. Conclusiones

 Comprendimos en este artículo cómo distinguir las versiones de IList: no-genérica y su contraparte genérico. También fue fundamental reconocer que este tipo de colección accede a los elementos integrantes a través de un índice (tal como sucede con los arreglos estándar.). Al final del artículo, vimos la interfaz genérica IReadOnlyList<T>: una vista de sólo lectura de IList<T>.

7. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
Learning the Concept of Arrays In Java (2017). Recuperado desde: http://www.javatutorialprograms.com/2015/11/learning-concept-of-arrays-in-java.html
IList Interface (System.Collections) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.collections.ilist(v=vs.110).aspx
IList(T) Interface (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/5y536ey6(v=vs.110).aspx
Interfaces ICollection y IList en C# - Parte 1/2 (2017). Recuperado desde: https://ortizol.blogspot.com.co/2017/08/interfaces-icollection-y-ilist-en-csharp-parte-1-2.html
Enumeración e Interfaces IEnumerator(T) e IEnumerable(T) en C# (2017). Recuperado desde: https://ortizol.blogspot.com.co/2017/08/enumeracion-e-interfaces-ienumerator-t-e-ienumerable-t-en-csharp.html
IReadOnlyList(T) Interface (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/hh192385(v=vs.110).aspx
C# y Windows Runtime (2017). Recuperado desde: https://ortizol.blogspot.com.co/2013/06/c-y-windows-runtime.html
out (Generic Modifier) (C# Reference) | Microsoft Docs (2017). Recuperado desde: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-generic-modifier


O

domingo, 20 de agosto de 2017

Interfaces ICollection y IList en C# - Parte 1/2

Índice

1. Introducción
2. Palabras Clave
3. Generalidades
4. ICollection y ICollection<T>
4.1 ICollection
4.2 ICollection<T>
5. Conclusiones
6. Literatura & Enlaces

1. Introducción

En los artículos pudimos comprender que la implementación de la enumeración sólo permite el recorrido -en una direccion-, de una colección: se pasa por cada uno de los elementos sin llevar a cabo ninguna otra operación. Ahora veremos que es posible efectuar otras operaciones interesantes sobre colecciones: conteo, agregación, eliminación o copiado de elementos, y entre otras más. Para ello es necesario que nos adentremos en el estudio de dos interfaces que provee .NET Framework: ICollection e IList.

2. Palabras Clave

  • Colección
  • Interfaz
  • Jerarquía de herencia
  • Lista
  • Nivel de funcionalidad

3. Generalidades

Vale insistir con la presentación de la jeraraquía de herencia de estas interfaces:
Jerarquía de herencia de interfaces de colección
Figura 1. Jerarquía de herencia de interfaces de colección (Albahari, 2012).
Otra manera de comprender y orientar la utilidad de estas interfaces es a través de su grado o nivel de funcionalidad (Albahari, 2012):
  • Funcionalidad mínima: sólo enumeración -IEnumerable y IEnumerable<T>-
  • Funcionalidad media: conteo, comprobación de existencia, remoción, etc. -ICollection y ICollection<T>-
  • Funcionalidad máxima: acceso aleatorio a elementos, inserción o eliminación por índice, etc. -IList<T>, IDictionary<K, V>-.
En Albahari (2012) se comenta que "It's rare that you'll need to implement any of these interfaces. In nearly all cases when you need to write a collection class, you can instead subclass Collection<T>."; es decir que en lugar de hacer implementaciones particulares de las interaces que ofrecen los distintos niveles de funcionalidad, es preferible extender/heredar de la clase Collection<T>.

La primera parte de este artículo se enfocará en el uso de las interfaces ICollection<T> y ICollection. La segunda entrega se entenderá con los temas IList<T>IList, y IReadOnlyList<T>.

4. ICollection y ICollection<T>

4.1 ICollection

La interfaz ICollection (namespace System.Collections) es la clase base para tipos de datos no genéricos. Los miembros abstractos definidos (Albahari, 2012):
  • int Count { get; }
  • bool isSynchronized { get; }
  • object SyncRoot { get; }
  • void CopyTo(Array, int)
Como se evidenciará a continuación, la versión genérica provee, además de los miembros anteriores, elementos de programa para modificar el contenido de la colección y comprobación de existencia de un elemento en la colección.

Continuando, ICollection implementa la interfaz IEnumerable para recorrer o listar los elementos pertenecientes a la colección.

4.2 ICollection<T>

La interfaz ICollection<T> cuenta con los miembros abstractos para la definición de una colección de tipos de datos genéricos.


Esta interfaz especializa a las interfaces IEnumerable y IEnumerable<T> para el recorrido de los elementos; y por lo tanto permitir el uso del ciclo foreach para la iteración.

Comparte algunos miembros en común con su contraparte no genérica y los propios suyos:

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }

    bool Contains (T item);
    void CopyTo (T[] array, int arrayIndex);
    bool IsReadOnly { get; }

    void Add(T item);
    bool Remove(T item);
    void Clear();
}


Si una colección de elementos está destinada a ser de sólo lectura, se recomienda lanzar la excepción NotSupportedException sobre los métodos Add, Remove, Clear (Albahari, 2012).

5. Conclusiones

En este artículo hemos comprendido la jerarquía de herencia de interfaces de colecciones. Inclusive, comprendimos cómo a medida que se aumenta la especialización o descendencia, los niveles de funcionalidad en las interfaces implementadoras aumentan. Al final observamos las propiedades y los métodos abstractos de las interfaces ICollection -no genérica- y ICollection<T> -genérica: destacando sus similitudes y diferencias sobresalientes.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
ICollection Interface (System.Collections) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.collections.icollection(v=vs.110).aspx
Enumeración e Interfaces IEnumerator e IEnumerable en C# (2017). Recuperado desde: https://ortizol.blogspot.com.co/2017/08/enumeracion-e-interfaces-ienumerator-e-ienumerable-en-csharp.html
ICollection(T) Interface (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/92t2ye13(v=vs.110).aspx#Syntax


O

domingo, 13 de agosto de 2017

Enumeración e Interfaces IEnumerator(T) e IEnumerable(T) en C#

Índice

1. Introducción
2. Palabras Clave
3. Interfaz IEnumerable<T>
4. Interfaz IEnumerator<T>
5. Implementación de Interfaces de Enumeración
6. Ejemplo de Uso
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

En el artículo anterior se presentaron las versiones no-genéricas de las interfaces IEnumerable y IEnumerator; ahora, llega la oportunidad de estudiar la utilidad y uso de las versiones genéricas: IEnumerable<T> y IEnumerator<T>. El ejemplo de uso que se presentará al final del artículo pretendenrán ser lo más explícito posibles, sin embargo se mantendrá la simplicidad en el código.

2. Palabras Clave

  • Clase genérica
  • Colección
  • Estructura de datos
  • Interfaz

3. Interfaz IEnumerable<T>

La interfaz IEnumerable<T> ("IEnumerable(T)", 2017) proporciona a un tipo de dato que represente una colección la capacidad de recorrer sus elementos en modo lectura. Principalmente esta interfaz está diseñada para trabajar con genericidad: la estructura o colección será capaz de enumerar o listar los elementos independiente del tipo de dato particular especificado para el tipo paramétrico.

Pongamos como ejemplo la clase List<T> ("List(T) Class", 2017). Esta clase permite especificar un tipo de dato concreto a almacenar en la estructura; así:

List<Tipo> lista = new List<Tipo>();

El tipo paramétrico Tipo será el tipo de dato de los elementos que se almacenen en la variable lista.

Supongamos ahora que agregamos elementos a la lista:

lista.add(new Tipo(...));
lista.add(new Tipo(...));
lista.add(new Tipo(...));
//...
lista.add(new Tipo(...));

Para recorrer la lista el programador puede usar el ciclo foreach:

foreach(Tipo tipo in lista){
    // ...
}

En el cuerpo del ciclo foreach se puede llevar a cabo operaciones de solo lectura sobre la colección almacenada en lista:List<T>.

Otras clases de colecciones que implementan esta interfaz:
  • Dictionary<TKey, TValue>
  • Stack<T>

4. Interfaz IEnumerator<T>

A través de la interfaz IEnumerator<T> ("IEnumerator(T) Interface", 2017) permite implementar la iteración o enumeración de los elementos de una colección de tipos genéricos. Vale enunciar que esta interfaz genérica herada de IEnumerator (Enumeración e Interfaces IEnumerator e IEnumerable en C#); esto se observa en la siguiente figura:
Jerarquía de herencia de enumeadores genéricos
Figura 1. Jerarquía de herencia de enumeadores genéricos (Albahari, 2012).
Al igual que su contraparte no genérica, las colecciones que implementan esta interfaz tienen habilitada la iteración de sus elementos a través del ciclo foreach. C# lo que hace es ocultar los detalles de la iteración de los elementos a través de esta versión del loop for.

Continuando, IEnumerator<T> implementa la interfaz IDisposable, permitiendo al proceso de enumeración llevar control de referencias a recursos de conexión a datos, y asegurar que éstos liberen los recursos utilizados cuando hayan terminado su ejecución (Albahari, 2012). Cuando se usa el ciclo foreach como en 

foreach(Tipo tipo in lista){
    // ...
}

internamente se está llevando a cabo la siguiente equivalencia

using(var enumerador = lista.GetEnumerator()){
    while(enumerador.MoveNext()){
        // ...
    }
}

5. Implementación Intefaces de Enumeración

En Albahari (2012) se exponen motivacionees para implementar estas interfaces:
  • Soportar el ciclo foreach
  • Interoperar con elementos de programa que requieran de una colección estándar
  • Soportar inicializadores de colecciones
  • Cumplir los requerimientos de interfaces de colecciones más avanzadas

6. Ejemplo de Uso

El siguiente ejemplo de uso permite demostrar cómo crear una colección personalizada, llamada Lista, con un tipo paramétrico. El constructor de esta clase permite establecer el número de elementos que contendrá la colección; y además, contiene un método para agregar elementos: void AgregarElemento(T).

Este código se compila y se ejecuta de la siguiente manera:

csc /out:Coleccion.exe Coleccion.cs

./Coleccion.exe


El resultado de la ejecución:

Dostoevsky
Balzac
Dickens


El código se puede probar en:

http://ideone.com/PvBaTX

7. Conclusiones

Este artículo aprendimos a distinguir la utilidad esencial de las interfaces IEnumerator y IEnumerable en sus versiones genéricas. Notamos que proveen al programador los mecanismos generales para iterar una colección que acepta tipos paramétricos para almacenar en su estructura de datos. El ejemplo es presentando tuvo como objetivo dar un vistazo general sobre cómo implementar la interfaz IEnumerable<T>, y retornar un objeto IEnumerator<T>.

El próximo artículo lo dedicaremos a estudiar las interfaces ICollection y IList.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.

A Beginner's Tutorial on Implementing IEnumerable Interface and Understanding yield Keyword - CodeProject (2017). Recuperado desde: https://www.codeproject.com/Articles/474678/A-Beginners-Tutorial-on-Implementing-IEnumerable-I
IEnumerable(T) Interface (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/9eekhta0%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
List(T) Class (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
IEnumerator(T) Interface (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/78dfe2yb(v=vs.110).aspx
Enumeración e Interfaces IEnumerator e IEnumerable en C# (2017). Recuperado desde: https://ortizol.blogspot.com/2017/08/enumeracion-e-interfaces-ienumerator-e-ienumerable-en-csharp.html


J

jueves, 10 de agosto de 2017

Enumeración e Interfaces IEnumerator e IEnumerable en C#

Índice

1. Introducción
2. Palabras Clave
3. Interfaz IEnumerable
4. Interfaz IEnumerator
5. Clase String
6. Ejemplo de Uso: Listar Nombres
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

En este artículo el programador C# aprenderá a distinguir la utilidad de dos interfaces fundamentales para implementar el recorrido de los elementos de una colección: IEnumerable y IEnumerator. Estas interfaces proveen los contratos de implementación que deben cumplir las estructuras de datos o colecciones para explorar su contenido a través del ciclo mejorado foreach.

2. Palabras Clave

  • Colección
  • Contrato
  • Enumeración
  • Estructura de datos
  • Interfaz

3. Interfaz IEnumerable

Este elemento de programa es una interfaz que expone un contrato de enumeración sobre colecciones o estructuras de datos no genéricas. En concreto, una colección debe escribir una implementación particular para el método GetEnumerator para devolver un elemento IEnumerator, el cual describe la lógica de recorrido.

Respecto a esta clase, hay que tener en cuenta la observación hallada en "IEnumerable Interface" (2017):
"It is a best practice to implement IEnumerable and IEnumerator on your collection classes to enable the foreach [...] syntax, however implementing IEnumerable is not required."
Esta consideración es importante a razón de que el programador puede omitir la implementación de IEnumerable y directamente utilizar la implementación de IEnumerator para hacer de una estructura de datos enumerable. Toda la lógica de recorrido se puede escribir en un tipo de dato que implemente esta última interfaz.

Sin embargo, en (Albahari, 2012) se considera a IEnumerable como un proveedor de enumeración o "IEnumeratorProvider". Lo que facilita exponer la lógica de recorrido en una clase/archivo independiente, pero sobretodo permite a diferentes secciones o locaciones de código hacer el recorrido de la colección sin interferir una con otra.

4. Interfaz IEnumerator

IEnumerator es un contrato o interfaz que dicta a un tipo de dato los métodos y propiedades que debe implementar para facilitar el recorrido de los elementos contenidos en la colección.

Los miembros que se deben implementar son los siguientes:
  • Propiedades:
    • Current: retorna el elemento de la posición actual de la colección.
  • Métodos:
    • MoveNext: mueve el índice a la siguiente posición de la colección.
    • Reset: posiciona el índice antes del primer elemento de la colección.
Al igual que la interfaz IEnumerable, IEnumerator está orientado para tipos de datos no genéricos. Para tipos de datos genéricos, el namespace System.Collections.Generic define las interfaces análogas IEnumerable<T>IEnumerator<T>.


En la Figura 1 (Albahari, 2012) se ilustra un esquema visual sobre la estructuración de estos tipos en .NET Framework:
Esquema de interfaces para colecciones
Figura 1. Esquema de interfaces para colecciones.

5. String

La clase String (namespace System) implementa la interfaz IEnumerable para enumerar cada uno de sus elementos: los caracteres que la integran:
Definición clase String
Figura 2. Definición clase String ("String Class", 2017).

Nótese en la imagen como esta clase implementa las versiones no-genéricas y genéricas de estas interfaces. En el próximo artículo se presenta la versión genérica de este tipo de protocolo o interfaz.

6. Ejemplo de Uso

El siguiente ejemplo de uso comprende 4 archivos de código fuente C# que demuestra cómo implementar las clases IEnumerable y IEnumerator para enumerar los elementos de una colección que contiene entidades Persona:
  • Persona.cs: Contiene la definición de la entidad que representa una persona con su nombre y apellido.
  • Gente.cs: Implementa la interfaz IEnumerable para retornar un objeto GenteEnumerator.
  • GenteEnumerator.cs: Implementa la interfaz IEnumerator con la lógica necesaria para desplazarse por cada uno de los elementos de la clase Persona.
  • App.cs: Código cliente que pone a prueba la enumeración de elementos de una colección de objetos Persona.
Archivo Gente.cs [enlace alternativo]:

Archivo GenteEnumerator.cs [enlace alternativo]:

Archivo App.cs [enlace alternativo]:

Para compilar este código basta con ejecutar el siguiente comando a través del compilador de C#:

csc /out:App.exe *.cs

La ejecución se lleva a cabo con:

./App.exe

El resultado de ejecutar esta aplicación es:

Fyodor Dostoevsky
Honoré Balzac

Charles Dickens

7. Conclusiones

Se presentaron las interfaz IEnumerable y IEnumerator. Se describió su utilidad para enumerar elementos de una colección o estructura de datos. Estas interfaces son protocolos estándar definidos en .NET Framework que permiten al programador C# sacar máximo provecho de los elementos estándar del lenguaje: el ciclo foreach.

En el siguiente artículo se explorarán las versiones análagas en genéricos de estas dos interfaces: IEnumerable<T> y IEnumerator<T>.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
IEnumerable Interface (System.Collections) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.collections.ienumerable(v=vs.110).aspx
String Class (System) (2017). Recuperado desde:
https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx


O