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));
For Each item As Producto In Repuestos CalcularTotal(item) Next o Repuestos = Repuestos _ .ForEach(Sub(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);
Dim Repuestos As IEnumerable(Of Producto) = Productos _ .Where(Function(prod) prod.Familia = "Repuestos") For Each item As Producto In Repuestos CalcularTotal(item) Next Dim MasVendidos As IEnumerable(Of Producto) = Repuestos _ .OrderByDescending(Function(rep) rep.TotalVentas) _ .Take(5) o Dim MasVendidos As IEnumerable(Of Producto) = Productos _ .Where(Function(prod) prod.Familia = "Repuestos") _ .ForEach(Sub(rep) CalcularTotal(rep)) _ .OrderByDescending(Function(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; } }
Module IEnumerableExtension <Extension()> Public Function ForEach(Of T)(source As IEnumerable(Of T) _ , action As Action(Of T)) As IEnumerable(Of T) If action Is Nothing Then Throw New ArgumentException("action") End If For Each item As T In source action(item) Next Return source End Function End Module
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