Tutorial: Escribir consultas en C# (LINQ)
Este tutorial muestra las características del lenguaje C# que se usan para escribir expresiones de consulta de LINQ.
Crear un proyecto de C#
Nota
Las siguientes instrucciones se aplican a Visual Studio. Si usa otro entorno de desarrollo, cree un proyecto de consola con una referencia a System.Core.dll y una directiva using
para el espacio de nombres System.Linq.
Para crear un proyecto en Visual Studio
Inicie Visual Studio.
En la barra de menús, elija Archivo, Nuevo, Proyecto.
Aparece el cuadro de diálogo Nuevo proyecto .
Expanda Instalado, Plantillas, Visual C# y luego elija Aplicación de consola.
En el cuadro de texto Nombre, escriba otro nombre o acepte el predeterminado y luego elija el botón Aceptar.
El proyecto nuevo aparece en el Explorador de soluciones.
Observe que el proyecto tiene una referencia a System.Core.dll y una directiva
using
para el espacio de nombres System.Linq.
Crear un origen de datos en memoria
El origen de datos de las consultas es una simple lista de objetos Student
. Cada registro Student
tiene un nombre, un apellido y una matriz de enteros que representa sus puntuaciones de las pruebas en la clase. Copie este código en el proyecto. Observe las siguientes características:
La clase
Student
consta de propiedades implementadas automáticamente.Cada alumno de la lista se inicializa con un inicializador de objeto.
La propia lista se inicializa con un inicializador de colección.
Toda la estructura de datos se inicializará y creará una instancia sin llamadas explícitas a ningún constructor ni acceso a miembro explícito. Para obtener más información sobre estas nuevas características, vea Propiedades autoimplementadas (Propiedades implementadas automáticamente) y Inicializadores de objeto y de colección.
Para agregar el origen de datos
Agregue la clase
Student
y la lista inicializada de alumnos a la claseProgram
del proyecto.public class Student { public string First { get; set; } public string Last { get; set; } public int ID { get; set; } public List<int> Scores; } // Create a data source by using a collection initializer. static List<Student> students = [ new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}}, new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}}, new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}}, new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}}, new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}}, new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}}, new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}}, new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}}, new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}}, new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}}, new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}}, new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}} ];
Para agregar un nuevo alumno a la lista de alumnos
- Agregue un nuevo
Student
a la listaStudents
y use el nombre y las puntuaciones de las pruebas que prefiera. Pruebe a escribir toda la nueva información de alumno para conocer mejor la sintaxis del inicializador de objeto.
Crear la consulta
Para crear una consulta simple
En el método
Main
de la aplicación, cree una consulta simple que, cuando se ejecute, genere una lista de todos los alumnos cuya puntuación en la primera prueba haya sido superior a 90. Tenga en cuenta que, dado que se ha seleccionado todo el objetoStudent
, el tipo de la consulta esIEnumerable<Student>
. Aunque el código podría usar tipos implícitos con la palabra clave var, se usan tipos explícitos para mostrar claramente los resultados. (Para obtener más información sobrevar
, vea Implicitly Typed Local Variables [Variables locales con tipo implícito]).Tenga también en cuenta que la variable de rango de la consulta,
student
, actúa como referencia a cadaStudent
del origen, lo que proporciona acceso a miembro para cada objeto.
// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
from student in students
where student.Scores[0] > 90
select student;
Ejecutar la consulta
Para ejecutar la consulta
Escriba ahora el bucle
foreach
que hará que la consulta se ejecute. Tenga en cuenta los siguiente sobre el código:A cada elemento de la secuencia devuelta se accede mediante la variable de iteración del bucle
foreach
.El tipo de esta variables es
Student
y el tipo de la variable de consulta es compatible,IEnumerable<Student>
.
Tras agregar este código, compile y ejecute la aplicación para ver los resultados en la ventana Consola.
// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
Console.WriteLine("{0}, {1}", student.Last, student.First);
}
// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael
Para agregar otra condición de filtro
Puede combinar varias condiciones booleanas en la cláusula
where
para delimitar aún más una consulta. El código siguiente agrega una condición para que la consulta devuelva los alumnos cuya primera puntuación haya sido superior a 90 y cuya última puntuación haya sido inferior a 80. La cláusulawhere
debería ser similar al código siguiente.where student.Scores[0] > 90 && student.Scores[3] < 80
Para obtener más información, vea where (Cláusula).
Modificar la consulta
Para ordenar los resultados
Le resultará más fácil examinar los resultados si se muestran con algún tipo de orden. Puede ordenar la secuencia devuelta por cualquier campo accesible de los elementos de origen. Por ejemplo, la cláusula
orderby
siguiente ordena los resultados alfabéticamente de la A a la Z por el apellido de cada alumno. Agregue la cláusulaorderby
siguiente a la consulta, inmediatamente después de la instrucciónwhere
y antes de la instrucciónselect
:orderby student.Last ascending
Cambie ahora la cláusula
orderby
para que ordene los resultados en orden inverso según la puntuación en la primera prueba, de la puntuación más alta a la más baja.orderby student.Scores[0] descending
Cambie la cadena de formato
WriteLine
para poder ver las puntuaciones:Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);
Para obtener más información, vea orderby (Cláusula).
Para agrupar los resultados
La agrupación es una funcionalidad de gran eficacia en expresiones de consulta. Una consulta con una cláusula group genera una secuencia de grupos y cada grupo propiamente dicho contiene un
Key
y una secuencia que consta de todos los miembros del grupo. La siguiente nueva consulta agrupa los alumnos usando la primera letra del apellido como clave.IEnumerable<IGrouping<char, Student>> studentQuery2 = from student in students group student by student.Last[0];
Tenga en cuenta que el tipo de la consulta ha cambiado. Ahora genera una secuencia de grupos que tienen un tipo
char
como clave y una secuencia de objetosStudent
. Dado que el tipo de la consulta ha cambiado, el siguiente código cambia también el bucle de ejecuciónforeach
:foreach (IGrouping<char, Student> studentGroup in studentQuery2) { Console.WriteLine(studentGroup.Key); foreach (Student student in studentGroup) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: // O // Omelchenko, Svetlana // O'Donnell, Claire // M // Mortensen, Sven // G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo // F // Fakhouri, Fadi // Feng, Hanying // T // Tucker, Lance // Tucker, Michael // A // Adams, Terry // Z // Zabokritski, Eugene
Ejecute la aplicación y vea los resultados en la ventana Consola.
Para obtener más información, vea group (Cláusula).
Para que las variables tengan tipo implícito
La codificación explícita con
IEnumerables
deIGroupings
puede resultar tediosa. Puede escribir la misma consulta y el bucleforeach
mucho más cómodamente convar
. La palabra clavevar
no cambia los tipos de los objetos; solo indica al compilador que deduzca los tipos. Cambie el tipo destudentQuery
y la variable de iteracióngroup
avar
y vuelva a ejecutar la consulta. Tenga en cuenta que en el bucleforeach
interior, la variable de iteración sigue teniendo como tipoStudent
y la consulta funciona igual que antes. Cambie la variable de iteraciónstudent
avar
y vuelva a ejecutar la consulta. Como puede ver, obtiene exactamente los mismos resultados.var studentQuery3 = from student in students group student by student.Last[0]; foreach (var groupOfStudents in studentQuery3) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: // O // Omelchenko, Svetlana // O'Donnell, Claire // M // Mortensen, Sven // G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo // F // Fakhouri, Fadi // Feng, Hanying // T // Tucker, Lance // Tucker, Michael // A // Adams, Terry // Z // Zabokritski, Eugene
Para obtener más información sobre var, vea Variables locales con asignación implícita de tipos.
Para ordenar los grupos por su valor clave
Al ejecutar la consulta anterior, observará que los grupos no están en orden alfabético. Para cambiar esto, debe especificar una cláusula
orderby
después de la cláusulagroup
. Pero para usar una cláusulaorderby
, necesita primero un identificador que actúe como referencia a los grupos creados por la cláusulagroup
. El identificador se especifica con la palabra claveinto
, de la manera siguiente:var studentQuery4 = from student in students group student by student.Last[0] into studentGroup orderby studentGroup.Key select studentGroup; foreach (var groupOfStudents in studentQuery4) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: //A // Adams, Terry //F // Fakhouri, Fadi // Feng, Hanying //G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo //M // Mortensen, Sven //O // Omelchenko, Svetlana // O'Donnell, Claire //T // Tucker, Lance // Tucker, Michael //Z // Zabokritski, Eugene
Cuando ejecute esta consulta, verá que los grupos aparecen ahora ordenados alfabéticamente.
Para incluir un identificador mediante let
Puede usar la palabra clave
let
para incluir un identificador con cualquier resultado de la expresión en la expresión de consulta. Este identificador puede resultar cómodo, como en el ejemplo siguiente, o mejorar el rendimiento almacenando los resultados de una expresión para que no tenga que calcularse varias veces.// studentQuery5 is an IEnumerable<string> // This query returns those students whose // first test score was higher than their // average score. var studentQuery5 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] where totalScore / 4 < student.Scores[0] select student.Last + " " + student.First; foreach (string s in studentQuery5) { Console.WriteLine(s); } // Output: // Omelchenko Svetlana // O'Donnell Claire // Mortensen Sven // Garcia Cesar // Fakhouri Fadi // Feng Hanying // Garcia Hugo // Adams Terry // Zabokritski Eugene // Tucker Michael
Para obtener más información, vea let (Cláusula).
Para usar la sintaxis de método en una expresión de consulta
Tal y como se describe en Sintaxis de consulta y sintaxis de método en LINQ, algunas operaciones de consulta solo pueden expresarse con una sintaxis de método. El código siguiente calcula la puntuación total de cada
Student
de la secuencia de origen y luego llama al métodoAverage()
en los resultados de esa consulta para calcular la puntuación media de la clase.var studentQuery6 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] select totalScore; double averageScore = studentQuery6.Average(); Console.WriteLine("Class average score = {0}", averageScore); // Output: // Class average score = 334.166666666667
Para transformar o proyectar en la cláusula select
Es muy frecuente que una consulta genere una secuencia cuyos elementos difieren de los elementos de las secuencias de origen. Elimine la consulta y el bucle de ejecución anteriores o conviértalos en comentario, y reemplácelos por el código siguiente. Tenga en cuenta que la consulta devuelve una secuencia de cadenas (no
Students
) y este hecho se refleja en el bucleforeach
.IEnumerable<string> studentQuery7 = from student in students where student.Last == "Garcia" select student.First; Console.WriteLine("The Garcias in the class are:"); foreach (string s in studentQuery7) { Console.WriteLine(s); } // Output: // The Garcias in the class are: // Cesar // Debra // Hugo
El código anterior en este tutorial indicaba que la puntuación media de la clase es aproximadamente 334. Para generar una secuencia de
Students
cuya puntuación total sea superior al promedio de la clase, junto con suStudent ID
, puede usar un tipo anónimo en la instrucciónselect
:
Pasos siguientes
Cuando se haya familiarizado con los aspectos básicos del uso de consultas en C#, estará preparado para leer la documentación y ejemplos del tipo específico de proveedor LINQ que le interese:
Vea también
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de