Relaciones entre tipos en operaciones de consulta (Visual Basic)
Las variables que se usan en las operaciones de consulta de consulta de Language-Integrated (LINQ) están fuertemente tipadas y deben ser compatibles entre sí. La tipificación fuerte se utiliza en la fuente de datos, en la propia consulta y en la ejecución de la consulta. En la ilustración siguiente se identifican los términos usados para describir una consulta LINQ. Para obtener más información sobre las partes de una consulta, vea Operaciones de consulta básicas (Visual Basic).
El tipo de la variable de rango en la consulta debe ser compatible con el tipo de los elementos en el origen de datos. El tipo de la variable de consulta debe ser compatible con el elemento de secuencia definido en la cláusula Select
. Por último, el tipo de los elementos de secuencia también debe ser compatible con el tipo de la variable de control de bucle que se usa en la instrucción For Each
que ejecuta la consulta. Esta escritura segura facilita la identificación de errores de tipo en tiempo de compilación.
Visual Basic facilita la escritura segura mediante la implementación de la inferencia de tipos locales, también conocida como escritura implícita. Esa característica se usa en el ejemplo anterior y verá que se usa en los ejemplos y la documentación de LINQ. En Visual Basic, la inferencia de tipos locales se realiza simplemente mediante el uso de una instrucción Dim
sin una cláusula As
. En el ejemplo siguiente, city
se escribe fuertemente como una cadena.
Dim city = "Seattle"
Nota
La inferencia de tipos locales solo funciona cuando Option Infer
se establece en On
. Para más información, consulte Instrucción (Option Infer).
Sin embargo, aunque use la inferencia de tipos local en una consulta, las mismas relaciones de tipo están presentes entre las variables del origen de datos, la variable de consulta y el bucle de ejecución de consultas. Resulta útil tener un conocimiento básico de estas relaciones de tipo al escribir consultas LINQ o trabajar con los ejemplos y ejemplos de código de la documentación.
Es posible que tenga que especificar un tipo explícito para una variable de rango que no coincida con el tipo devuelto desde el origen de datos. Puede especificar el tipo de la variable de rango mediante una cláusula As
. Sin embargo, esto produce un error si la conversión es una conversión de restricción y Option Strict
se establece en On
. Por lo tanto, se recomienda realizar la conversión en los valores recuperados del origen de datos. Puede convertir los valores del origen de datos al tipo de variable de rango explícito mediante el método Cast. También puede convertir los valores seleccionados en la cláusula Select
a un tipo explícito diferente del tipo de la variable de intervalo. Algunos puntos se ilustran en el código siguiente.
Dim numbers1() As Integer = {1, 2, 4, 16, 32, 64}
Dim numbers2() As Double = {5.0#, 10.0#, 15.0#}
' This code does not result in an error.
Dim numberQuery1 = From n As Integer In numbers1 Where n > 5
' This code results in an error with Option Strict set to On. The type Double
' cannot be implicitly cast as type Integer.
Dim numberQuery2 = From n As Integer In numbers2 Where n > 5
' This code casts the values in the data source to type Integer. The type of
' the range variable is Integer.
Dim numberQuery3 = From n In numbers2.Cast(Of Integer)() Where n > 5
' This code returns the value of the range variable converted to Integer. The type of
' the range variable is Double.
Dim numberQuery4 = From n In numbers2 Where n > 5 Select CInt(n)
Consultas que devuelven elementos completos de los datos de origen
En el ejemplo siguiente se muestra una operación de consulta LINQ que devuelve una secuencia de elementos seleccionados a partir de los datos de origen. El origen, names
, contiene una matriz de cadenas y la salida de la consulta es una secuencia que contiene cadenas que comienzan por la letra M.
Dim names = {"John", "Rick", "Maggie", "Mary"}
Dim mNames = From name In names
Where name.IndexOf("M") = 0
Select name
For Each nm In mNames
Console.WriteLine(nm)
Next
Esto equivale al código siguiente, pero es mucho más corto y fácil de escribir. La dependencia de la inferencia de tipos local en las consultas es el estilo preferido en Visual Basic.
Dim names2 = {"John", "Rick", "Maggie", "Mary"}
Dim mNames2 As IEnumerable(Of String) =
From name As String In names
Where name.IndexOf("M") = 0
Select name
For Each nm As String In mNames
Console.WriteLine(nm)
Next
Las relaciones siguientes existen en ambos ejemplos de código anteriores, tanto si los tipos se determinan implícita o explícitamente.
El tipo de los elementos del origen de datos,
names
, es el tipo de la variable de rango,name
, en la consulta.El tipo del objeto que está seleccionado,
name
, determina el tipo de la variable de consulta,mNames
. Estaname
es una cadena, por lo que la variable de consulta es IEnumerable(Of String) en Visual Basic.La consulta definida en
mNames
se ejecuta en el bucleFor Each
. El bucle recorre en iteración el resultado de ejecutar la consulta. Dado quemNames
, cuando se ejecuta, devolverá una secuencia de cadenas, la variable de iteración de bucle,nm
, también es una cadena.
Consultas que devuelven un campo de los elementos seleccionados
En el ejemplo siguiente se muestra una operación de consulta LINQ to SQL que devuelve una secuencia que contiene solo una parte de cada elemento seleccionado del origen de datos. La consulta toma una colección de objetos Customer
como su origen de datos y proyecta solo la propiedad Name
en el resultado. Como el nombre del cliente es una cadena, la consulta produce una secuencia de cadenas como salida.
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim custNames = From cust In customers
Where cust.City = "London"
Select cust.Name
For Each custName In custNames
Console.WriteLine(custName)
Next
Las relaciones entre variables son similares a las del ejemplo más sencillo.
El tipo de los elementos del origen de datos,
customers
, es el tipo de la variable de rango,cust
, en la consulta. En este ejemplo, ese tipo esCustomer
.La instrucción
Select
devuelve la propiedadName
de cada objetoCustomer
en lugar de todo el objeto. Dado queName
es una cadena, la variable de consulta,custNames
, volverá a ser IEnumerable(Of String), no deCustomer
.Dado que
custNames
es una secuencia de cadenas, la variable de iteración del bucleFor Each
,custName
, debe ser una cadena.
Sin inferencia de tipos locales, el ejemplo anterior sería más complicado escribir y comprender, como se muestra en el ejemplo siguiente.
' Method GetTable returns a table of Customer objects.
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)()
Dim custNames As IEnumerable(Of String) =
From cust As Customer In customers
Where cust.City = "London"
Select cust.Name
For Each custName As String In custNames
Console.WriteLine(custName)
Next
Consultas que requieren tipos anónimos
En el siguiente ejemplo se muestra una situación más compleja. En el ejemplo anterior, era inconveniente especificar tipos para todas las variables explícitamente. En este ejemplo, es imposible. En lugar de seleccionar elementos Customer
completos del origen de datos, o un único campo de cada elemento, la cláusula Select
de esta consulta devuelve dos propiedades del objeto original Customer
: Name
y City
. En respuesta a la cláusula Select
, el compilador define un tipo anónimo que contiene esas dos propiedades. El resultado de la ejecución de nameCityQuery
en el bucle For Each
es una colección de instancias del nuevo tipo anónimo. Dado que el tipo anónimo no tiene ningún nombre utilizable, no puede especificar el tipo de nameCityQuery
o custInfo
explícitamente. Es decir, con un tipo anónimo, no tiene ningún nombre de tipo que se use en lugar de String
en IEnumerable(Of String)
. Para obtener más información, consulte Tipos anónimos (Guía de programación de C#).
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim nameCityQuery = From cust In customers
Where cust.City = "London"
Select cust.Name, cust.City
For Each custInfo In nameCityQuery
Console.WriteLine(custInfo.Name)
Next
Aunque no es posible especificar tipos para todas las variables del ejemplo anterior, las relaciones siguen siendo las mismas.
El tipo de los elementos del origen de datos es de nuevo el tipo de la variable de rango en la consulta. En el ejemplo,
cust
es una instancia deCustomer
.Dado que la instrucción
Select
genera un tipo anónimo, la variable de consulta,nameCityQuery
, debe declararse implícitamente mediante un tipo anónimo. Un tipo anónimo no tiene ningún nombre utilizable y, por tanto, no se puede especificar explícitamente.El tipo de la variable de iteración en el bucle
For Each
es el tipo anónimo creado en el paso 2. Dado que el tipo no tiene ningún nombre utilizable, el tipo de la variable de iteración de bucle debe determinarse implícitamente.