Relaciones entre tipos en operaciones de consulta LINQ (C#)
Para escribir las consultas eficazmente, es necesario comprender cómo los tipos de las variables en una operación de consulta completa se relacionan entre sí. Si entiende estas relaciones comprenderá más fácilmente los ejemplos de LINQ y los ejemplos de código de la documentación. Además, comprenderá lo que ocurre cuando las variables se escriben implícitamente mediante var
.
las operaciones de consulta LINQ tienen un establecimiento fuertemente tipado en el origen de datos, en la propia consulta y en la ejecución de la consulta. El tipo de las variables de la consulta debe ser compatible con el tipo de los elementos del origen de datos y con el tipo de la variable de iteración de la instrucción foreach
. Este establecimiento inflexible de tipos garantiza que los errores de tipos se detectan en tiempo de compilación, cuando aún se pueden corregir antes de que los usuarios los detecten.
Para mostrar estas relaciones de tipos, en la mayoría de los ejemplos siguientes se usan tipos explícitos para todas las variables. En el último ejemplo se muestra cómo se aplican los mismos principios incluso cuando se usa la escritura implícita mediante var
.
Consultas que no transforman los datos de origen
La ilustración siguiente muestra una operación de consulta de LINQ to Objects que no realiza ninguna transformación de los datos. El origen contiene una secuencia de cadenas y el resultado de la consulta también es una secuencia de cadenas.
- El argumento de tipo del origen de datos determina el tipo de la variable de rango.
- El tipo del objeto que está seleccionado determina el tipo de la variable de consulta. Aquí,
name
es una cadena. Por tanto, la variable de consulta esIEnumerable<string>
. - La variable de consulta se procesa en iteración en la instrucción
foreach
. Dado que la variable de consulta es una secuencia de cadenas, la variable de iteración también es una cadena.
Consultas que transforman los datos de origen
En la ilustración siguiente se muestra una operación de consulta de LINQ to SQL que realiza una transformación simple de los datos. La consulta usa una secuencia de objetos Customer
como entrada y selecciona solo la propiedad Name
en el resultado. Dado que Name
es una cadena, la consulta genera una secuencia de cadenas como resultado.
- El argumento de tipo del origen de datos determina el tipo de la variable de rango.
- La instrucción
select
devuelve la propiedadName
en lugar del objetoCustomer
completo. Dado queName
es una cadena, el argumento de tipo decustNameQuery
esstring
, noCustomer
. - Dado que
custNameQuery
es una secuencia de cadenas, la variable de iteración del bucleforeach
también debe serstring
.
En la ilustración siguiente se muestra una transformación un poco más compleja. La instrucción select
devuelve un tipo anónimo que captura solo dos miembros del objeto Customer
original.
- El argumento de tipo del origen de datos siempre es el tipo de la variable de rango de la consulta.
- Dado que la instrucción
select
genera un tipo anónimo, la variable de consulta debe declararse implícitamente mediantevar
. - Dado que el tipo de la variable de consulta es implícito, la variable de iteración del bucle
foreach
también debe ser implícita.
Permitir que el compilador deduzca la información de tipo
Aunque debería comprender las relaciones de los tipos en una operación de consulta, tiene la opción de que el compilador le haga todo el trabajo. La palabra clave var se puede usar para cualquier variable local en una operación de consulta. La ilustración siguiente es similar al ejemplo número 2 que se ha analizado anteriormente. En cambio, el compilador proporciona el tipo seguro de cada variable en la operación de consulta.
LINQ y tipos genéricos (C#)
Las consultas LINQ se basan en tipos genéricos. No es necesario tener conocimientos avanzados de genéricos para poder empezar a escribir consultas, aunque debería entender dos conceptos básicos:
- Al crear una instancia de una clase de colección genérica como List<T>, reemplace la "T" por el tipo de objetos que contendrá la lista. Por ejemplo, una lista de cadenas se expresa como
List<string>
y una lista de objetosCustomer
se expresa comoList<Customer>
. Las listas genéricas están fuertemente tipadas y ofrecen muchas ventajas respecto a las colecciones que almacenan sus elementos como Object. Si intenta agregar unCustomer
a unaList<string>
, se producirá un error en tiempo de compilación. Usar colecciones genéricas es fácil porque no es necesario efectuar ninguna conversión de tipos en tiempo de ejecución. - IEnumerable<T> es la interfaz que permite enumerar las clases de colección genéricas mediante la instrucción
foreach
. Las clases de colección genéricas admiten IEnumerable<T> simplemente como clases de colección no genéricas como ArrayList admite IEnumerable.
Para obtener más información sobre los genéricos, vea Genéricos.
Variables IEnumerableT<> en consultas LINQ
Las variables de consulta LINQ tienen el tipo IEnumerable<T> o un tipo derivado como IQueryable<T>. Cuando vea una variable de consulta que tiene el tipo IEnumerable<Customer>
, significa que, al ejecutarse, la consulta generará una secuencia de cero o más objetos Customer
.
IEnumerable<Customer> customerQuery =
from cust in customers
where cust.City == "London"
select cust;
foreach (Customer customer in customerQuery)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Permitir que el compilador controle las declaraciones de tipo genérico
Si lo prefiere, puede evitar la sintaxis genérica mediante la palabra clave var. La palabra clave var
indica al compilador que infiera el tipo de una variable de consulta examinando el origen de datos especificado en la cláusula from
. En el ejemplo siguiente se genera el mismo código compilado que en el ejemplo anterior:
var customerQuery2 =
from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
La palabra clave var
es útil cuando el tipo de la variable es obvio o cuando no es tan importante especificar explícitamente los tipos genéricos anidados, como los que generan las consultas de grupo. Le recordamos que, si usa var
, debe tener presente que puede dificultar la lectura del código a otros usuarios. Para más información, vea Variables locales con asignación implícita de tipos.