¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. C# 10 y Visual Studio Code
  3. LINQ
Extrait - C# 10 y Visual Studio Code Fundamentos del lenguaje
Extractos del libro
C# 10 y Visual Studio Code Fundamentos del lenguaje
1 opinión
Volver a la página de compra del libro

LINQ

Funcionamiento básico

Las expresiones lambda llegaron con la versión 3 del lenguaje C# y han transformado la rutina diaria de los programadores. Una expresión lambda, también llamada una lambda, es una manera de escribir una función directamente dentro de una línea sin tener que definirla explícitamente dentro de la clase. La ventaja de este planteamiento es que, a partir de ese momento, esta función se puede usar como variable y ser ejecutada por otra función, e incluso pasarse directamente a una función. Esta manera nueva de escribir una función (también llamada a veces función flecha) es un método abreviado muy apreciado y ampliamente utilizado. Además, a partir de la versión 3 del framework .NET, Microsoft incluyó un sistema nuevo de gestión de las colecciones: LINQ (Language INtegrated Query).

Es frecuente que los programadores se tengan que enfrentar a una base de datos durante la creación de un proyecto. Muchos conocen el lenguaje SQL, norma extendida para los sistemas de gestión de bases de datos relacionales.

Desde una perspectiva de mutualización de las competencias, Microsoft introdujo LINQ dentro del framework .NET para que los desarrolladores .NET pudieran considerar a todas las colecciones como una base de datos y tuvieran un lenguaje de consulta dentro del código C# similar al proporcionado...

Variables anónimas

C# es un lenguaje fuertemente tipado, lo que hace que un objeto de un tipo dado no pueda cambiar de tipo durante su existencia. Sin embargo, con la llegada de LINQ se quiere recuperar un conjunto de valores que tienen una agrupación lógica, pero sin hacer una clase o una estructura definida.

Con la versión 3 de C# se ha introducido el concepto de variable anónima. Se trata de crear un objeto, fuertemente tipado, pero que no pertenece a un tipo conocido ni declarado. Esta flexibilidad permite crear un objeto a medida, que siempre respeta todas las limitaciones. Por ejemplo, si queremos crear un coche sin tener que definir una clase para alojar los datos relacionados, escribimos el siguiente código:

var coche = new { Marca = "Peugeot", Caballos = 120, Funciona = true }; 

Como se puede comprobar, no hay tipo después de la instrucción new. La apertura de las llaves permite definir directamente la lista de las propiedades que contendrá este objeto. Esta flexibilidad es muy útil para generar de inmediato un objeto como retorno de la consulta LINQ, a fin de producir un objeto nuevo a partir de datos de una colección de objetos conocidos.

Principios de los operadores LINQ

De manera nativa, LINQ proporciona una gran cantidad de operadores. Si la lista propuesta no es suficiente para usted, hay un proyecto comunitario que añade muchos otros: https://github.com/morelinq/MoreLINQ. Por nuestra parte, nos conformaremos con estudiar en este capítulo los que se proporcionan de manera nativa en el framework.

En primer lugar, hay que comprender que LINQ funciona en un orden inverso al de SQL. En efecto, es frecuente que una consulta de SQL simple se formule de esta manera:

SELECT ... FROM Table WHERE ... ORDER BY ... 

Al traducir esta consulta a español, se obtiene la siguiente lógica: en la tabla Table (FROM), donde se aplica una condición (WHERE), ordenando las líneas según un orden (ORDER BY), recupérame las siguientes columnas (SELECT).

Los operadores LINQ toman como parámetro una lambda que define lo que se espera mediante el método. La mayoría de las lambdas para LINQ están formadas de la siguiente manera: la lambda toma como parámetro la instancia actual que corresponde al elemento actual de las colecciones y la usa en el cuerpo de la función. Se puede pasar por una función clásica para obtener el mismo resultado. Así, las dos maneras siguientes de escribir son similares:

public void TestLinq() 
{ 
    List<int> l = new() 
    { 
           1, 2, 3, 4, 5, 6, 7, 8, 9 
    }; 
    var enteros = l.Where(i => i < 3); 
    var enteros2 = l.Where(Filtro); 
} 
 
public bool Filtro(int i) 
{ 
    return i < 3; 
} 

El segundo caso es menos frecuente porque el nombre de la función que debe ser llamada para el filtro se pasa como parámetro al operador LINQ. Esto solo funciona si la función tiene el número, tipos de parámetros y tipo de devolución correctos; por eso se recomienda usar las funciones flecha.

Algunos operadores trabajan con un valor de la colección y producen un retorno bajo la forma de un booleano, ya que es una prueba que se evalúa para cada...

Expresión de consulta LINQ

Hasta ahora, hemos hablado de LINQ desde el punto de vista de los métodos de extensión en la interfaz IEnumerable<T>. Sin embargo, LINQ ofrece otra sintaxis, llamada expresión de consulta (o query expression en inglés). Esta última se acerca a un formalismo que se parece más a lo que se puede encontrar en SQL, incluso si el orden lógico está invertido.

En efecto, cuando se usa este enfoque, hay que empezar por describir el nombre de la variable con la que se quiere trabajar dentro de una colección dada, usando el formalismo from ... in ...

Después de esta extracción, se pueden añadir uno o varios operadores:

  • where.

  • orderby/orderby ... descending. De forma predeterminada, el operador order by funciona de manera ascendente sin que sea necesario especificarlo. Sin embargo, para que sea explícito se puede añadir la palabra clave ascending.

  • thenby/thenby ... descending. De forma predeterminada, then by funciona de manera ascendente sin que sea necesario especificarlo. Sin embargo, para que sea explícito se puede añadir la palabra clave ascending.

  • group ... by ....

  • join.

La consulta termina con un select.

Por ejemplo:

var enteros = new List<int> { 1, 2, 3, 4, 5 }; 
var clasificacion = from i in enteros where i > 2 orderby 
i descending select  
i.ToString(); // tendremos una colección de cadenas, que contiene  
los enteros superiores a 2, clasificados en orden decreciente 

Como se puede comprobar, esta manera de escribir una consulta LINQ se acerca al SQL, a excepción de la inversión de la lógica de selección (el operador...

Ejercicio

Es el momento de poner en práctica lo que hemos visto en este capítulo sobre LINQ.

1. Enunciado

Este ejercicio consiste en generar (usando operadores LINQ) una lista de enteros, de 1 a 100, y devolver solo la lista de los números divisibles entre 7. Para que el ejercicio no sea demasiado sencillo, se pide escribir las consultas LINQ bajo las dos formas que se han estudiado: mediante métodos de extensión y con la expresión de consulta.

Los números resultado son 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91 y 98.

Una vez obtenido este resultado, se divide en dos grupos: los números pares y los números impares. Cada uno de los grupos obtenidos se identifica por su nombre (par o impar) y contiene los números correspondientes.

Aquí se puede ver un ejemplo de visualización de lo que se espera:

images/05_03.png

Resultados de ejecución esperados para el ejercicio

La doble presencia de los números en la parte superior se explica por el hecho de que las dos consultas LINQ han sido iteradas (la que contiene los métodos de extensión y la que contiene la expresión de consulta LINQ). Para obtener un desfase uniforme entre los números, se puede usar la tabulación, insertando el carácter \t dentro de la cadena.

2. Solución

El código para llegar a este resultado es el siguiente:

using System; 
using System.Linq; 
 
var enteros...