Condividi tramite


Funzionalità C# che supportano LINQ

Espressioni di query

Le espressioni di query usano una sintassi dichiarativa simile a SQL o XQuery per eseguire query sulle System.Collections.Generic.IEnumerable<T> raccolte. Durante la fase di compilazione, il compilatore converte la sintassi delle query in chiamate ai metodi dell'implementazione di un provider LINQ dei metodi di query standard. Le applicazioni controllano gli operatori di query standard che sono nell'ambito specificando lo spazio dei nomi appropriato tramite una direttiva using. L'espressione di query seguente accetta una matrice di stringhe, le raggruppa in base al primo carattere nella stringa e ordina i gruppi.

var query = from str in stringArray
            group str by str[0] into stringGroup
            orderby stringGroup.Key
            select stringGroup;

Variabili tipizzate in modo implicito (var)

È possibile usare il modificatore var per indicare al compilatore di dedurre e assegnare il tipo, come illustrato di seguito:

var number = 5;
var name = "Virginia";
var query = from str in stringArray
            where str[0] == 'm'
            select str;

Le variabili dichiarate come var sono fortemente tipate, esattamente come le variabili di cui si specifica il tipo in modo esplicito. L'uso var consente di creare tipi anonimi, ma solo per le variabili locali. Per altre informazioni, vedere Variabili locali tipizzate in modo implicito.

Inizializzatori di oggetti e raccolte

Gli inizializzatori di oggetti e raccolte consentono di inizializzare gli oggetti senza chiamare in modo esplicito un costruttore per l'oggetto . In genere si usano gli inizializzatori nelle espressioni di query quando proiettano i dati di origine in un nuovo tipo di dati. Supponendo che esista una classe chiamata Customer con proprietà pubbliche Name e Phone, è possibile usare l'inizializzatore dell'oggetto come nel codice seguente:

var cust = new Customer { Name = "Mike", Phone = "555-1212" };

Continuando con la Customer classe, si supponga che sia presente un'origine dati denominata IncomingOrderse che per ogni ordine con un oggetto di grandi dimensioni OrderSizesi vuole creare un nuovo Customer oggetto in base a tale ordine. È possibile eseguire una query LINQ su questa origine dati e usare l'inizializzazione degli oggetti per riempire una raccolta:

var newLargeOrderCustomers = from o in IncomingOrders
                            where o.OrderSize > 5
                            select new Customer { Name = o.Name, Phone = o.Phone };

L'origine dati potrebbe avere più proprietà definite rispetto alla Customer classe , OrderSizead esempio , ma con l'inizializzazione degli oggetti, i dati restituiti dalla query vengono modellati nel tipo di dati desiderato. È possibile scegliere i dati rilevanti per la classe. Di conseguenza, ora hai un System.Collections.Generic.IEnumerable<T> pieno dei nuovi Customer che desideravi. È anche possibile scrivere l'esempio precedente nella sintassi del metodo LINQ:

var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone });

A partire da C# 12, è possibile usare un'espressione di raccolta per inizializzare una raccolta.

Per altre informazioni, vedere:

Tipi anonimi

Il compilatore costruisce un tipo anonimo. Solo il compilatore può accedere al nome del tipo. I tipi anonimi consentono di raggruppare temporaneamente un set di proprietà in un risultato di query senza dover definire un tipo denominato separato. Inizializzare i tipi anonimi con una nuova espressione e un inizializzatore di oggetto, come illustrato di seguito:

select new {name = cust.Name, phone = cust.Phone};

A partire da C# 7, è possibile usare le tuple per creare tipi senza nome.

Membri dell'estensione

Un membro di estensione è un membro statico di una classe statica associata a un tipo denominato tipo di ricevitore. È possibile chiamare un membro di estensione come se fosse un membro del tipo di ricevitore. Questa funzionalità consente di "aggiungere" nuovi membri ai tipi esistenti senza modificarli effettivamente. Gli operatori di query standard sono un set di metodi di estensione che forniscono funzionalità di query LINQ per qualsiasi tipo che implementa IEnumerable<T>.

Espressioni lambda

Un'espressione lambda è una funzione inline che usa l'operatore => per separare i parametri di input dal corpo della funzione e può essere convertita in fase di compilazione in un delegato o in un albero delle espressioni. Nella programmazione LINQ si riscontrano espressioni lambda quando si effettuano chiamate di metodo diretto agli operatori di query standard.

Espressioni come dati

Gli oggetti query sono componibili, ovvero è possibile restituire una query da un metodo . Gli oggetti che rappresentano le query non archiviano la raccolta risultante, ma piuttosto i passaggi per produrre i risultati quando necessario. Il vantaggio della restituzione di oggetti query dai metodi consiste nel fatto che è possibile comporre o modificarli ulteriormente. Pertanto, qualsiasi valore restituito o out parametro di un metodo che restituisce una query deve avere anche tale tipo. Se un metodo materializza una query in un tipo concreto List<T> o Array, restituisce i risultati della query anziché la query stessa. È comunque possibile comporre o modificare una variabile di query restituita da un metodo.

Nell'esempio seguente il primo metodo QueryMethod1 restituisce una query come valore restituito e il secondo metodo QueryMethod2 restituisce una query come out parametro (returnQ nell'esempio). In entrambi i casi, si tratta di una query restituita, non dei risultati della query.

IEnumerable<string> QueryMethod1(int[] ints) =>
    from i in ints
    where i > 4
    select i.ToString();

void QueryMethod2(int[] ints, out IEnumerable<string> returnQ) =>
    returnQ = from i in ints
              where i < 4
              select i.ToString();

int[] nums = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];

var myQuery1 = QueryMethod1(nums);

Il ciclo seguente foreach esegue la query myQuery1.

foreach (var s in myQuery1)
{
    Console.WriteLine(s);
}

Posizionare il puntatore del mouse su myQuery1 per visualizzarne il tipo.

È anche possibile eseguire direttamente la query restituita da QueryMethod1, senza usare myQuery1.

foreach (var s in QueryMethod1(nums))
{
    Console.WriteLine(s);
}

Posizionare il puntatore del mouse sulla chiamata a QueryMethod1 per visualizzare il tipo restituito.

QueryMethod2 restituisce una query come valore del relativo out parametro:

QueryMethod2(nums, out IEnumerable<string> myQuery2);

// Execute the returned query.
foreach (var s in myQuery2)
{
    Console.WriteLine(s);
}

È possibile modificare una query utilizzando la composizione delle interrogazioni. In questo caso, l'oggetto query precedente viene usato per creare un nuovo oggetto query. Questo nuovo oggetto restituisce risultati diversi rispetto all'oggetto query originale.

myQuery1 = from item in myQuery1
           orderby item descending
           select item;

// Execute the modified query.
Console.WriteLine("\nResults of executing modified myQuery1:");
foreach (var s in myQuery1)
{
    Console.WriteLine(s);
}