Clausola from (Riferimento C#)
Aggiornamento: novembre 2007
Un'espressione di query deve iniziare con la clausola from. Inoltre, un'espressione di query può contenere sottoquery che iniziano anch'esse con la clausola from. La clausola from specifica gli elementi seguenti:
Origine dati su cui la query o la sottoquery verrà eseguita.
Variabile di intervallo locale che rappresenta ogni elemento nella sequenza di origine.
Sia la variabile di intervallo che l'origine dati sono fortemente tipizzate. L'origine dati a cui si fa riferimento nella clausola from deve contenere un tipo di IEnumerable, IEnumerable<T> o un tipo derivato, ad esempio IQueryable<T>.
Nell'esempio riportato di seguito, numbers è l'origine dati e num è la variabile di intervallo. Si noti che entrambe le variabili sono fortemente tipizzate anche se viene utilizzata la parola chiave var.
class LowNums
{
static void Main()
{
// A simple data source.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// Create the query.
// lowNums is an IEnumerable<int>
var lowNums = from num in numbers
where num < 5
select num;
// Execute the query.
foreach (int i in lowNums)
{
Console.Write(i + " ");
}
}
}
// Output: 4 1 3 2 0
Variabile di intervallo
Tramite l'inferenza, il compilatore deriva il tipo della variabile di intervallo quando l'origine dati implementa IEnumerable<T>. Se, ad esempio, l'origine dispone di un tipo di IEnumerable<Customer>, la variabile di intervallo dedotta sarà Customer. È necessario specificare il tipo in modo esplicito unicamente quando l'origine è un tipo IEnumerable non generico, ad esempio ArrayList. Per ulteriori informazioni, vedere la classe Procedura: eseguire una query su un ArrayList con LINQ.
Nell'esempio precedente, si deduce che num è di tipo int. Poiché la variabile di intervallo è fortemente tipizzata, è possibile chiamare metodi su di essa o utilizzarla in altre operazioni. Ad esempio, anziché scrivere select num, è possibile scrivere select num.ToString() in modo che l'espressione di query restituisca una sequenza di stringhe anziché numeri interi. Oppure è possibile scrivere select n + 10 in modo che l'espressione restituisca la sequenza 14, 11, 13, 12 10. Per ulteriori informazioni, vedere Clausola select (Riferimento C#).
La variabile di intervallo è analoga a una variabile di iterazione nell'istruzione foreach eccetto che per una differenza molto importante: una variabile di intervallo non archivia effettivamente mai dati dall'origine. Si tratta semplicemente di un vantaggio sintattico che consente alla query di descrivere ciò che si verificherà quando la query verrà eseguita. Per ulteriori informazioni, vedere la classe Introduzione alle query LINQ.
Clausole from composte
In alcuni casi, ogni elemento nella sequenza di origine può essere una sequenza o contenere una sequenza. Ad esempio, l'origine dati può essere un oggetto IEnumerable<Student> in cui ciascun elemento studente della sequenza contiene un elenco di punteggi del test. Per accedere all'elenco interno in ogni elemento Student è possibile utilizzare clausole from composte. La tecnica è analoga all'uso di istruzioni foreach nidificate. È possibile aggiungere clausole where o orderby a una delle due clausole from per filtrare i risultati. Nell'esempio seguente viene illustrata una sequenza di oggetti Student, ognuno dei quali contiene un List interno di numeri interi che rappresentano i punteggi del test. Per accedere all'elenco interno, utilizzare una clausola from composta. Se necessario, è possibile inserire delle clausole tra le due clausole from.
class CompoundFrom
{
// The element type of the data source.
public class Student
{
public string LastName { get; set; }
public List<int> Scores {get; set;}
}
static void Main()
{
// Use a collection initializer to create the data source. Note that
// each element in the list contains an inner sequence of scores.
List<Student> students = new List<Student>
{
new Student {LastName="Omelchenko", Scores= new List<int> {97, 72, 81, 60}},
new Student {LastName="O'Donnell", Scores= new List<int> {75, 84, 91, 39}},
new Student {LastName="Mortensen", Scores= new List<int> {88, 94, 65, 85}},
new Student {LastName="Garcia", Scores= new List<int> {97, 89, 85, 82}},
new Student {LastName="Beebe", Scores= new List<int> {35, 72, 91, 70}}
};
// Use a compound from to access the inner sequence within each element.
// Note the similarity to a nested foreach statement.
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
// Execute the queries.
Console.WriteLine("scoreQuery:");
foreach (var student in scoreQuery)
{
Console.WriteLine("{0} Score: {1}", student.Last, student.score);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/
Utilizzo di più clausole from per eseguire join
Una clausola from composta viene utilizzata per accedere a insiemi interni in una sola origine dati. Una query può tuttavia contenere anche più clausole from che generano query supplementari dalle origini dati indipendenti. Questa tecnica consente di eseguire determinati tipi di operazioni di join che non sono possibili utilizzando la clausola join.
Nell'esempio seguente viene mostrato come due clausole from possono essere utilizzate per formare un cross join completo di due origini dati.
class CompoundFrom2
{
static void Main()
{
char[] upperCase = { 'A', 'B', 'C'};
char[] lowerCase = { 'x', 'y', 'z'};
var joinQuery1 =
from upper in upperCase
from lower in lowerCase
select new { upper, lower};
var joinQuery2 =
from lower in lowerCase
where lower != 'x'
from upper in upperCase
select new { lower, upper };
// Execute the queries.
Console.WriteLine("Cross join:");
foreach (var pair in joinQuery1)
{
Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
}
Console.WriteLine("Filtered non-equijoin:");
foreach (var pair in joinQuery2)
{
Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Cross join:
A is matched to x
A is matched to y
A is matched to z
B is matched to x
B is matched to y
B is matched to z
C is matched to x
C is matched to y
C is matched to z
Filtered non-equijoin:
y is matched to A
y is matched to B
y is matched to C
z is matched to A
z is matched to B
z is matched to C
*/
Per ulteriori informazioni sulle operazioni di join che utilizzano più clausole from, vedere Procedura: eseguire operazioni di join personalizzate (Guida per programmatori C#).
Vedere anche
Concetti
Espressioni query LINQ (Guida per programmatori C#)