Relazioni tra i tipi nelle operazioni di query (Visual Basic)

Le variabili utilizzate nelle operazioni di query LINQ (Language-Integrated Query) sono fortemente tipizzate e devono essere compatibili tra loro. La tipizzazione forte viene utilizzata nell'origine dati, nella query stessa e nell'esecuzione della query. Nella figura seguente vengono identificati i termini utilizzati per descrivere una query LINQ. Per ulteriori informazioni sulle parti di una query, vedere Operazioni di query di base (Visual Basic).

Parti di una query LINQ

Query pseudocodice con elementi evidenziati.

Il tipo della variabile di intervallo nella query deve essere compatibile con il tipo degli elementi nell'origine dati. Il tipo della variabile di query deve essere compatibile con l'elemento della sequenza definito nella clausola Select. Infine, il tipo degli elementi della sequenza deve essere compatibile anche con il tipo della variabile di controllo del ciclo utilizzata nell'istruzione For Each che esegue la query. Questa tipizzazione forte semplifica l'identificazione degli errori di tipo in fase di compilazione.

In Visual Basic la tipizzazione forte viene applicata implementando l'inferenza del tipo di variabile locale, nota anche come tipizzazione implicita. Questa funzionalità viene utilizzata nell'esempio precedente e in tutti gli esempi e nella documentazione LINQ. In Visual Basic l'inferenza del tipo di variabile locale viene eseguita semplicemente utilizzando un'istruzione Dim senza una clausola As. Nell'esempio seguente city è fortemente tipizzato come stringa.

Dim city = "Seattle"

Nota

L'inferenza del tipo di variabile locale funziona solo quando Option Infer è impostato su On. Per ulteriori informazioni, vedere Istruzione Option Infer.

Tuttavia, anche se si utilizza l'inferenza del tipo di variabile locale in una query, le stesse relazioni tra i tipi sono presenti tra le variabili nell'origine dati, la variabile di query e il ciclo di esecuzione della query. È utile avere una comprensione di base di queste relazioni tra i tipi quando si scrivono le query LINQ o si utilizzano gli esempi e gli esempi di codice presenti nella documentazione.

Potrebbe essere necessario specificare un tipo esplicito per una variabile di intervallo che non corrisponde al tipo restituito dall'origine dati. È possibile specificare il tipo della variabile di intervallo utilizzando una clausola As. In questo modo, tuttavia, viene restituito un errore se la conversione è una conversione verso un tipo di dati più piccolo e Option Strict è impostato su On. Si consiglia pertanto di eseguire la conversione sui valori recuperati dall'origine dati. È possibile convertire i valori dall'origine dati nel tipo di variabile di intervallo esplicito utilizzando il metodo Cast<TResult>. È inoltre possibile eseguire il cast dei valori selezionati nella clausola Select a un tipo esplicito diverso dal tipo della variabile di intervallo. Questi punti vengono illustrati nel codice seguente.

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)

Query che restituiscono elementi dell'origine dati completi

Nell'esempio seguente viene illustrata un'operazione di query LINQ che restituisce una sequenza di elementi selezionati dai dati di origine. Il database di origine, names, contiene una matrice di stringhe e il risultato della query è una sequenza contenente stringhe che iniziano con la lettera 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

Questo equivale al codice seguente, ma è molto più breve e facile da scrivere. L'utilizzo dell'inferenza del tipo di variabile locale nelle query è lo stile preferito in 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

Le relazioni riportate di seguito sono presenti in entrambi gli esempi di codice precedenti, indipendentemente dal fatto che i tipi vengano determinati in modo implicito o esplicito.

  1. Il tipo degli elementi nell'origine dati, names, è il tipo della variabile di intervallo, name, nella query.

  2. Il tipo dell'oggetto selezionato, name, determina il tipo della variabile di query mNames. In questo caso name è una stringa, pertanto la variabile di query è IEnumerable(Of String) in Visual Basic.

  3. La query definita in mNames viene eseguita nel ciclo For Each. Il ciclo scorre il risultato dell'esecuzione della query. Poiché mNames, quando viene eseguito, restituisce una sequenza di stringhe, anche la variabile di iterazione del ciclo, nm, è una stringa.

Query che restituiscono un campo dagli elementi selezionati

Nell'esempio seguente viene illustrata un'operazione di query LINQ to SQL che restituisce una sequenza contenente solo una parte di ogni elemento selezionato dall'origine dati. La query utilizza un insieme di oggetti Customer come origine dati e proietta solo la proprietà Name nel risultato. Poiché il nome cliente è una stringa, la query genera una sequenza di stringhe come output.

' 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

Le relazioni tra le variabili sono simili a quelle riportate nell'esempio più semplice.

  1. Il tipo degli elementi nell'origine dati, customers, è il tipo della variabile di intervallo, cust, nella query. In questo esempio, il tipo è Customer.

  2. L'istruzione Select restituisce la proprietà Name di ogni oggetto Customer anziché l'intero oggetto. Poiché Name è una stringa, la variabile di query, custNames, sarà di nuovo IEnumerable(Of String), non Customer.

  3. Poiché custNames rappresenta una sequenza di stringhe, la variabile di iterazione del ciclo For Each, custName, deve essere una stringa.

Senza l'inferenza del tipo di variabile locale, l'esempio precedente risulterebbe più complesso da scrivere e da comprendere, come illustrato nell'esempio seguente.

' 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

Query che richiedono tipi anonimi

Nell'esempio seguente viene illustrata una situazione più complessa. Nell'esempio precedente non era utile specificare i tipi per tutte le variabili in modo esplicito. In questo esempio non è possibile. Anziché selezionare gli elementi Customer completi dall'origine dati o un singolo campo da ogni elemento, la clausola Select in questa query restituisce due proprietà dell'oggetto Customer originale: Name e City. In risposta alla clausola Select, il compilatore definisce un tipo anonimo che contiene quelle due proprietà. Il risultato dell'esecuzione di nameCityQuery nel ciclo For Each è un insieme di istanze del nuovo tipo anonimo. Poiché il tipo anonimo non ha un nome utilizzabile, non è possibile specificare il tipo di nameCityQuery o custInfo in modo esplicito. Ovvero, con un tipo anonimo non è disponibile alcun nome del tipo da utilizzare al posto di String in IEnumerable(Of String). Per ulteriori informazioni, vedere Anonymous Types.

' 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

Anche se non è possibile specificare i tipi per tutte le variabili nell'esempio precedente, le relazioni restano invariate.

  1. Il tipo degli elementi nell'origine dati è ancora una volta il tipo della variabile di intervallo nella query. In questo esempio cust è un'istanza di Customer.

  2. Poiché l'istruzione Select genera un tipo anonimo, la variabile di query, nameCityQuery, deve essere tipizzata in modo implicito come tipo anonimo. Un tipo anonimo non ha un nome utilizzabile e pertanto non può essere specificato in modo esplicito.

  3. Il tipo della variabile di iterazione nel ciclo For Each è il tipo anonimo creato nel passaggio 2. Poiché il tipo non dispone di nomi utilizzabili, il tipo della variabile di iterazione del ciclo deve essere determinato in modo implicito.

Vedere anche

Concetti

Anonymous Types

Local Type Inference

Introduction to LINQ in Visual Basic

Altre risorse

Introduzione a LINQ in Visual Basic

LINQ in Visual Basic

Query (Visual Basic)