Compartir a través de


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).

Screenshot showing a pseudocode query with elements highlighted.

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.

  1. El tipo de los elementos del origen de datos, names, es el tipo de la variable de rango, name, en la consulta.

  2. El tipo del objeto que está seleccionado, name, determina el tipo de la variable de consulta, mNames. Esta name es una cadena, por lo que la variable de consulta es IEnumerable(Of String) en Visual Basic.

  3. La consulta definida en mNames se ejecuta en el bucle For Each. El bucle recorre en iteración el resultado de ejecutar la consulta. Dado que mNames, 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.

  1. 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 es Customer.

  2. La instrucción Select devuelve la propiedad Name de cada objeto Customer en lugar de todo el objeto. Dado que Name es una cadena, la variable de consulta, custNames, volverá a ser IEnumerable(Of String), no de Customer.

  3. Dado que custNames es una secuencia de cadenas, la variable de iteración del bucle For 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.

  1. 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 de Customer.

  2. 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.

  3. 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.

Consulte también