Condividi tramite


Relazioni tra tipi nelle operazioni di query (Visual Basic)

Le variabili usate nelle operazioni di query LINQ (Language-Integrated Query) sono fortemente tipate e devono essere compatibili tra loro. La tipizzazione forte viene usata nell'origine dati, nella query stessa e nell'esecuzione della query. La figura seguente identifica i termini usati per descrivere una query LINQ. Per altre informazioni sulle parti di una query, vedere Operazioni di query di base (Visual Basic).

Screenshot che mostra una pseudocodice di query con gli 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 sequenza definito nella Select clausola . Infine, il tipo degli elementi della sequenza deve essere compatibile anche con il tipo della variabile di controllo ciclo usata nell'istruzione For Each che esegue la query. Questa digitazione avanzata facilita l'identificazione degli errori di tipo in fase di compilazione.

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

Dim city = "Seattle"

Annotazioni

L'inferenza del tipo locale funziona solo quando Option Infer è impostata su On. Per altre informazioni, vedere Istruzione Option Infer.

Tuttavia, anche se si usa l'inferenza del tipo locale in una query, le stesse relazioni di tipo sono presenti tra le variabili nell'origine dati, la variabile di query e il ciclo di esecuzione della query. È utile avere una conoscenza di base di queste relazioni tra tipi quando si scrivono query LINQ o si consultano gli esempi e il codice 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 usando una As clausola . Tuttavia, viene generato un errore se la conversione è una conversione verso un tipo di dati più piccolo e Option Strict è impostato su On. È pertanto consigliabile eseguire la conversione sui valori recuperati dall'origine dati. È possibile convertire i valori dall'origine dati al tipo di variabile di intervallo esplicito usando il Cast metodo . È anche possibile fare il cast dei valori selezionati nella clausola Select a un tipo esplicito che sia diverso dal tipo della variabile di intervallo. Questi punti sono 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 interi elementi dei dati di origine

Nell'esempio seguente viene illustrata un'operazione di query LINQ che restituisce una sequenza di elementi selezionati dai dati di origine. L'origine, names, contiene una matrice di stringhe e l'output 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

Equivale al codice seguente, ma è molto più breve e più facile da scrivere. La preferenza per l'inferenza dei tipi locali 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 seguenti esistono 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. Ecco name una stringa, quindi la variabile di query è IEnumerable(Of String) in Visual Basic.

  3. La query definita in mNames viene eseguita nel For Each ciclo . Il ciclo itera sui risultati dell'esecuzione della query. Poiché mNames, quando viene eseguito, restituirà una sequenza di stringhe, la variabile di iterazione del ciclo, , nmè anche 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 una sola parte di ogni elemento selezionato dall'origine dati. La query accetta una raccolta di Customer oggetti come origine dati e proietta solo la Name proprietà nel risultato. Poiché il nome del cliente è una stringa, la query produce 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 dell'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 Name proprietà di ogni Customer oggetto anziché l'intero oggetto. Poiché Name è una stringa, la variabile di query, custNames, sarà nuovamente IEnumerable(Of String), non di Customer.

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

Senza inferenza del tipo locale, l'esempio precedente sarebbe più complesso da scrivere e 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

L'esempio seguente mostra una situazione più complessa. Nell'esempio precedente era poco pratico specificare i tipi per tutte le variabili in modo esplicito. In questo esempio, è impossibile. Anziché selezionare interi Customer elementi dall'origine dati o un singolo campo da ogni elemento, la Select clausola in questa query restituisce due proprietà dell'oggetto originale Customer : Name e City. In risposta alla Select clausola , il compilatore definisce un tipo anonimo che contiene queste due proprietà. Il risultato dell'esecuzione nameCityQuery nel For Each ciclo è una raccolta 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 si dispone di alcun nome di tipo da usare al posto di String in IEnumerable(Of String). Per altre informazioni, vedere Tipi anonimi.

' 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 tipi per tutte le variabili nell'esempio precedente, le relazioni rimangono invariate.

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

  2. Poiché l'istruzione Select produce 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 For Each ciclo è il tipo anonimo creato nel passaggio 2. Poiché il tipo non ha un nome utilizzabile, il tipo della variabile di iterazione del ciclo deve essere determinato in modo implicito.

Vedere anche