Condividi tramite


Relazioni tra tipi nelle operazioni di query LINQ (C#)

Per scrivere query in modo efficace, è necessario comprendere in che modo i tipi di variabili in un'operazione di query completa sono tutti correlati tra loro. Se si conoscono queste relazioni, è possibile comprendere più facilmente gli esempi di codice e gli esempi di codice LINQ nella documentazione. Si comprenderà anche cosa accade quando le variabili vengono tipizzate in modo implicito usando var.

Le operazioni di query LINQ sono strettamente tipizzate nell'origine dati, nella query stessa e durante l'esecuzione della query. Il tipo delle variabili nella query deve essere compatibile con il tipo degli elementi nell'origine dati e con il tipo della variabile di iterazione nell'istruzione foreach . Questa tipizzazione avanzata garantisce che gli errori di tipo vengano rilevati in fase di compilazione quando possono essere corretti prima che gli utenti li incontrino.

Per illustrare queste relazioni di tipo, la maggior parte degli esempi seguenti usa la digitazione esplicita per tutte le variabili. L'ultimo esempio mostra come si applicano gli stessi principi anche quando si usa la digitazione implicita usando var.

Query che non trasformano i dati di origine

La figura seguente illustra un'operazione di query LINQ to Objects che non esegue trasformazioni sui dati. L'origine contiene una sequenza di stringhe e l'output della query è anche una sequenza di stringhe.

Diagramma che mostra la relazione dei tipi di dati in una query LINQ.

  1. L'argomento di tipo dell'origine dati determina il tipo della variabile di intervallo.
  2. Il tipo dell'oggetto selezionato determina il tipo della variabile di query. Ecco una stringa name. Pertanto, la variabile di query è un oggetto IEnumerable<string>.
  3. La variabile di query viene iterata nell'istruzione foreach . Poiché la variabile di query è una sequenza di stringhe, la variabile di iterazione è anche una stringa.

Query che trasformano i dati di origine

La figura seguente illustra un'operazione di query LINQ to SQL che esegue una semplice trasformazione sui dati. La query accetta una sequenza di Customer oggetti come input e seleziona solo la Name proprietà nel risultato. Poiché Name è una stringa, la query produce una sequenza di stringhe come output.

Diagramma che mostra una query che trasforma il tipo di dati.

  1. L'argomento di tipo dell'origine dati determina il tipo della variabile di intervallo.
  2. L'istruzione select restituisce la Name proprietà anziché l'oggetto completo Customer . Poiché Name è una stringa, l'argomento di tipo di custNameQuery è string, non Customer.
  3. Poiché custNameQuery è una sequenza di stringhe, anche la foreach variabile di iterazione del ciclo deve essere .string

La figura seguente mostra una trasformazione leggermente più complessa. L'istruzione select restituisce un tipo anonimo che acquisisce solo due membri dell'oggetto originale Customer .

Diagramma che mostra una query più complessa che trasforma il tipo di dati.

  1. L'argomento di tipo dell'origine dei dati è sempre il tipo della variabile di intervallo nella query.
  2. Poiché l'istruzione select produce un tipo anonimo, la variabile di query deve essere tipizzata in modo implicito tramite var.
  3. Poiché il tipo della variabile di query è implicito, anche la foreach variabile di iterazione nel ciclo deve essere implicita.

Consentire al compilatore di dedurre le informazioni sul tipo

Anche se è necessario comprendere le relazioni tra i tipi in un'operazione di query, è possibile consentire al compilatore di eseguire tutte le operazioni. La parola chiave var può essere usata per qualsiasi variabile locale in un'operazione di query. La figura seguente è simile al numero di esempio 2 illustrato in precedenza. Tuttavia, il compilatore fornisce il tipo sicuro per ogni variabile nell'operazione di query.

Diagramma che mostra il flusso di tipi con tipizzazione implicita.

Tipi LINQ e generici (C#)

Le query LINQ sono basate su tipi generici. Non è necessaria una conoscenza approfondita dei generics prima di iniziare a scrivere query. Tuttavia, è possibile comprendere due concetti di base:

  1. Quando si crea un'istanza di una classe di raccolta generica, List<T>ad esempio , si sostituisce "T" con il tipo di oggetti che l'elenco conterrà. Ad esempio, un elenco di stringhe viene espresso come List<string>e un elenco di Customer oggetti viene espresso come List<Customer>. Un elenco generico è fortemente tipizzato e offre molti vantaggi rispetto alle raccolte che archiviano i relativi elementi come Object. Se si tenta di aggiungere un Customer oggetto a un List<string>oggetto , verrà visualizzato un errore in fase di compilazione. È facile usare raccolte generiche perché non è necessario eseguire la conversione dei tipi durante l'esecuzione.
  2. IEnumerable<T> è l'interfaccia che consente l'enumerazione delle classi di raccolte generiche tramite l'istruzione foreach . Le classi di raccolta generiche supportano IEnumerable<T>, proprio come le classi di raccolta non generiche, come ArrayList, supportano IEnumerable.

Per altre informazioni sui generics, vedere Generics.

Variabili IEnumerable< T> nelle query LINQ

Le variabili di query LINQ vengono tipate come IEnumerable<T> o un tipo derivato, IQueryable<T>ad esempio . Quando viene visualizzata una variabile di query tipizzata come IEnumerable<Customer>, significa semplicemente che la query, quando viene eseguita, produrrà una sequenza di zero o più Customer oggetti.

IEnumerable<Customer> customerQuery = from cust in customers
                                      where cust.City == "London"
                                      select cust;

foreach (Customer customer in customerQuery)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Consentire al compilatore di gestire le dichiarazioni di tipo generico

Se si preferisce, è possibile evitare la sintassi generica usando la parola chiave var . La var parola chiave indica al compilatore di dedurre il tipo di una variabile di query esaminando l'origine dati specificata nella from clausola . L'esempio seguente produce lo stesso codice compilato dell'esempio precedente:

var customerQuery2 = from cust in customers
                     where cust.City == "London"
                     select cust;

foreach(var customer in customerQuery2)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

La var parola chiave è utile quando il tipo della variabile è ovvio o quando non è importante specificare in modo esplicito tipi generici annidati, ad esempio quelli prodotti dalle query di gruppo. In generale, raccomandiamo che se si utilizza var, si tenga presente che questo può rendere il codice più difficile da leggere per altri utenti. Per altre informazioni, vedere Variabili locali tipizzate in modo implicito.