Una entrada que pudiera ser no merecedora de un espacio para
ella sola. La cláusula Let,
tiene una serie de virtudes que van desde una mejora notable en la lectura y
comprensión del código, hasta un incremento en el rendimiento por la reducción
de llamadas redundantes.
La única nota negativa, pero no menos importante, es que
esta cláusula, solo puede utilizarse con sintaxis de consulta (azúcar sintáctico), por lo que nuestras queridas Lambdas se quedan fuera.
Recuerda que aquí tienes el indice de todos los posts del Curso de LinQ.
A nivel general la cláusula Let nos permite crear una variable local a nivel de consulta.
El mecanismo es exactamente el mismo al que utilizamos cuando generamos una variable
a nivel local dentro de un método o de un bucle.
Veamos a ver un ejemplo, que es bastante más representativo.
Esta será la clase o entidad que utilizaremos para nuestros
ejemplos:
public class Tienda
{
public string Nombre { get; set; }
public decimal Ventas { get; set; }
public DateTime FechaApertura { get; set; }
public override string ToString() => $"Nombre:{Nombre} - Ventas:{Ventas} - FechaAp:{FechaApertura}";
public static IEnumerable<Tienda> GenerarTiendas()
{
return new List<Tienda>()
{
new Tienda { Nombre = "La tienda magica" , Ventas = 1000000m, FechaApertura = new DateTime(1998, 1, 1) },
new Tienda { Nombre = "La peor de las tiendas", Ventas = 10m, FechaApertura = new DateTime(2001, 2, 25) },
new Tienda { Nombre = "La tienda exotérica" , Ventas = 2000000m, FechaApertura = new DateTime(1990, 9, 1) },
new Tienda { Nombre = "Otra tienda mas" , Ventas = 8000000m, FechaApertura = new DateTime(2015, 3, 2) }
};
}
}
Este es el primer ejemplo:
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 3 'a' en su nombre, que su aniversario cae en viernes este año
/// y que tienen más de 990.000 de ventas
var tiendasFiltro = from t in tiendas
where t.Nombre.Where(n => n == 'a').Count() > 3
&& new DateTime(DateTime.Today.Year, t.FechaApertura.Month, t.FechaApertura.Day).DayOfWeek == DayOfWeek.Friday
&& t.Ventas > 990000m
select t;
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine(tienda);
}
Console.Read();
}
Como vemos la consulta tiene mucha parte de lógica de
negocio y se hace complicada su lectura. Esto lo podríamos arreglar creando un
método local para cada una de las comparaciones, pero la cláusula Let, nos va a ahorrar este trabajo y
nos va a dar la comprensión y lectura de código que buscamos:
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 3 'a' en su nombre, que su aniversario cae en viernes este año
/// y que tienen más de 990.000 de ventas
var tiendasFiltro = from t in tiendas
let letrasA = t.Nombre.Where(n => n == 'a').Count()
let diaAñoActual = new DateTime(DateTime.Today.Year, t.FechaApertura.Month, t.FechaApertura.Day).DayOfWeek
where letrasA > 3
&& diaAñoActual == DayOfWeek.Friday
&& t.Ventas > 990000m
select t;
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine(tienda);
}
Console.Read();
}
La cláusula Let, también nos puede ayudar para aunar funcionalidad,
para en caso de cambio tener que modificar el código en un solo lugar.
En el siguiente ejemplo haremos un filtrado de tiendas que
tienen más de 10 años de vida y que han vendido de media más de 10.000 al año:
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 10 años de vida
/// y que tienen más de 10.000 de ventas por año
var tiendasFiltro = from t in tiendas
where DateTime.Today.Year - t.FechaApertura.Year > 10
&& t.Ventas / (DateTime.Today.Year - t.FechaApertura.Year) > 10000
select t;
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine(tienda);
}
Console.Read();
}
En esta consulta, se repetiría 2 veces la llamada a la
porción de código que comprueba el nº de años:
DateTime.Today.Year - t.FechaApertura.Year > 10
Además tendríamos que tocar en 2 sitios diferentes en caso
de querer cambiar esta fórmula.
Let, nos ayuda, y lo deja así de bonito:
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 10 años de vida
/// y que tienen más de 10.000 de ventas por año
var tiendasFiltro = from t in tiendas
let diferenciaAños = DateTime.Today.Year - t.FechaApertura.Year
where diferenciaAños > 10
&& t.Ventas / (diferenciaAños) > 10000
select t;
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine(tienda);
}
Console.Read();
}
Y el resultado, por supuesto el mismo:
Todo esto se agrava, cuando dentro de nuestras consultas,
personalizamos la salida mediante el operador Select y agregamos alguno de los resultados de estas pequeñas
reglas de negocio. Vamos a ver un ejemplo (una pequeña modificación del anterior):
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 10 años de vida
/// y que tienen más de 10.000 de ventas por año
var tiendasFiltro = from t in tiendas
where DateTime.Today.Year - t.FechaApertura.Year > 10
&& t.Ventas / (DateTime.Today.Year - t.FechaApertura.Year) > 10000
select new
{
NombreTienda = t.Nombre,
AñosDeExistencia = DateTime.Today.Year - t.FechaApertura.Year,
VentasMediasPorAño = t.Ventas / (DateTime.Today.Year - t.FechaApertura.Year)
};
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine($"Nombre:{tienda.NombreTienda} - Años de Existencia: {tienda.AñosDeExistencia} - Ventas Medias Por Año: {tienda.VentasMediasPorAño.ToString("N2")}");
}
Console.Read();
}
Código repetido a mansalva, ejecuciones redundantes por
todos lados.
Vamos a
arreglarlo:
static void Main(string[] args)
{
var tiendas = Tienda.GenerarTiendas();
/// Tiendas que tienen más de 10 años de vida
/// y que tienen más de 10.000 de ventas por año
var tiendasFiltro = from t in tiendas
let diferenciaAños = DateTime.Today.Year - t.FechaApertura.Year
where diferenciaAños > 10
&& t.Ventas / (diferenciaAños) > 10000
select new
{
NombreTienda = t.Nombre,
AñosDeExistencia = diferenciaAños,
VentasMediasPorAño = t.Ventas / (diferenciaAños)
};
foreach(var tienda in tiendasFiltro)
{
Console.WriteLine($"Nombre:{tienda.NombreTienda} - Años de Existencia: {tienda.AñosDeExistencia} - Ventas Medias Por Año: {tienda.VentasMediasPorAño.ToString("N2")}");
}
Console.Read();
}
No hay comentarios :
Publicar un comentario