sábado, 16 de mayo de 2015

.NET Framework. Método de extensión ForEach para IEnumerable

Desde la aparición de Linq muchos nos hemos hecho auténticos adictos de esta librería, hasta el punto de que si ahora nos la quitasen tendríamos que reinventarla.

Tareas que antes producían decenas de líneas de código difícil de entender y de mantener, de repente pasaban a poder implementarse en una sola instrucción, lo que redundaba en un incremento en la productividad, la claridad del código y su mantenibilidad.

Sin embargo, dentro de los métodos de extensión de la interfaz IEnumerable<T>, muchos hemos echado de menos un método que nos permita realizar una acción sobre todos los elementos de la colección: un método ForEach.

A decir verdad la implementación de un método ForEach para la interfaz IEnumerable<T> tiene sus defensores y sus detractores.

Hay quien argumenta que entre estos dos códigos:

    foreach (Producto item in Repuestos)
        CalcularTotal(item);

o

    Repuestos = Repuestos
        .ForEach(item => CalcularTotal(item));

resulta más legible el primero y, por tanto, el método de extensión no aporta nada (o al menos nada bueno). Y yo estoy absolutamente de acuerdo con ellos.

Sin embargo los métodos de extensión de Linq tienen otra gran ventaja: su capacidad para poder llamarse de manera encadenada.



Si elegimos otro ejemplo

    IEnumerable<Producto> Repuestos = Productos
        .Where(prod => prod.Familia == "Repuestos");

    foreach (Producto item in Repuestos)
        CalcularTotal(item);

    IEnumerable<Producto> MasVendidos = Repuestos
        .OrderByDescending(rep => rep.TotalVentas)
        .Take(5);

o

    IEnumerable<Producto> MasVendidos = Productos
        .Where(prod=>prod.Familia=="Repuestos")
        .ForEach(rep=>CalcularTotal(rep))
        .OrderByDescending(rep=>rep.TotalVentas)
        .Take(5);

podemos ver que el método de extensión ForEach sí que puede mejorar la legibilidad de nuestro código en algunos casos.

De hecho este método viene ya implementado en las clases System.Array o System.Collections.Generic.List<T>.

Para crear el método de extensión voy a crear una Clase estática IEnumerableExtension en C# o un Módulo con el mismo nombre en VB.NET. La Clase o el Módulo contendrá un único método genérico ForEach con dos parámetros:


  • El primer parámetro, como cualquier método de extensión, representa el objeto de la clase o interfaz que estamos extendiendo sobre el que se aplicará el método. En este caso una instancia de la interfaz IEnumerable<T>.
  • El segundo parámetro define la acción a aplicar a cada elemento de la enumeración y consistirá en un método con un único parámetro de tipo T.


    static class IEnumerableExtension
    {
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source
            , Action<T> action)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            foreach (T item in source)
                action(item);

            return source;
        }
    }

Y ya tenemos el método listo para usar en nuestro código. No olvides añadir la referencia al Namespace de la clase en el archivo de código donde desees utilizarlo mediante un using (en C#) o Imports (en VB.NET).


No hay comentarios:

Publicar un comentario