C# 3.0: Query Expressions

C# 3.0: Query Expressions

  • Comments 4

Der har været lavet en del usability studier omkring anvendelsen af lambdaudtryk i .NET. Feedback har været lambdaudtryk kan være temmelig svære at læse og skrive for manger OO-udviklere. Derfor er der lavet lidt syntaktisk sukker over lambdaudtryk, således de bliver lettere at læse/skrive. Resultatet er Query Expressions. Her er et par collections som jeg bruger til at lave en forespørgsel på:

List<Customer> customers = new List<Customer> { new Customer{Name="Henrik", Order=3},
  
new Customer{Name="Jeppe",Order=1}, new Customer{Name="Bo", Order=2}};
Dictionary<int, string> orders = new Dictionary<int, string> {
   {1, "Silverlight 2.0"},{2, "All about management"}, {3, "More on F#"} };

I og med at de begge implementerer IEnumerable<T> så kan vi lave forespørgsler på dem, da der er lavet extension methodsIEnumerable<T> interfacet. En forespørgsel som joiner customers og orders ved hjælp af lambdaudtryk, projekterer customer.Name og order.Value ud, samt sorterer efter customer.Name ser ud som følgende:

var
lambda = customers.Join( orders, cust => cust.Order,
   order => order.Key,
   (cust, order)=> new { Name = cust.Name, Order=order.Value })
   .OrderBy(c=>c.Name);

Umiddelbart er jeg tilbøjelig til at give alle usability studierne ret – det er ikke særlig læsbart, hvis ikke man er vandt funktionelle programmeringssprog. Extension metoden Join tager 4 parametrer, hvor den første parameter er typen der skal joines (Dictonary orders), så gives en lambda der mapper joinnøglen til customer og efterfølgende en lambda der mapper joinnøglen i orders, og til sidst resultatet. Se MSDN dokumentationen for flere info.

Hvis man skal skrive ovenstående lambdaQuery om til at anvende Query Expressions, så vil det på mere læsevenlig form kunne skrives som følgende:

var query = from c in customers
  
join o in orders
  
on c.Order equals o.Key
  
orderby c.Name
  
select new { Name = c.Name, OrderText = o.Value };

Begge queries giver følgende resultat når jeg laver en foreach over dem:

{ Name = Bo, Order = All about management }
{ Name = Henrik, Order = More on F# }
{ Name = Jeppe, Order = Silverlight 2.0 }

Der er en meget bekvem .ToString() metode på anonyme typer således man kan udskrive alle properties på en anonym type.

Oftest plejer programmører at kløjes i syntaksen. Hvorfor kommer select til sidst og from først? Sådan gør man jo ikke i SQL?

For det første så er det ikke SQL, men LINQ. LINQ er et generelt forespørgselssprog som bruges mod mange datakilder og ikke kun relationelle databaser (her er det objekter). Desuden kan man sige, at i imperative programmeringssprog definerer man variabler før man bruger dem. Træerne vokser dog heller ikke ind i himlen. På et tidspunkt vil du nok lave et "fallback" til lambdaer, da det ikke er alle operatorer/extension methods der er implementeret. Jeg hører til den gruppe, der foretrækker lambdaer:-)

Her er lidt ressourcer hvis du vil læse mere om Query Expressions:

  • Så vidt jeg husker er syntaksen omvendt i VB, altså ligesom SQL. Så man får SELECT...FROM i stedet for FROM...SELECT som i C#

  • Hej Kristian

    Du husker rigtigt - sådan var det. VB havde denne syntaks ret langt op i CTP/Beta frigivelserne. På et tidspunkt opgav man at lave SQL syntaksen i VB. Jeg mener det blev for svært blandt andet at lave intellisenseunderstøttelse da man i SQL ikke definere variable før man bruger dem, hvilket vi gør i imperative programmeringssprog.

    Så VB følger nu samme syntaks.

    /Henrik

  • Jeg er enig i din post når vi kommer til Join queries, til næsten alle andre operationer benytter jeg inline lambda'er, det synes jeg er væsentligt lettere at læse samtidig med at det er mere kortfattet. Jeg bryder mig dog ikke om "x equals y" syntaksen, lad mig venligst skrive "x == y".

    Jeg så også gerne en gang sukker ovenpå den eksisterende sukker så:

    customers.Join(orders, cust => cust.Order, order => order.Key, (cust, order) => new { cust.Name, order.Value })

    =>

    customers.Join(orders, (cust, order) => cust.Order == order.Key, (cust, order) => new { cust.Name, order.Value })

    Sidstnævnte eksempel mener jeg er væsentligt mere letlæseligt, og jeg kan ikke se hvad der skulle umuliggøre det. Der vil naturligvis være de samme begrænsninger i Linq2SQL delen ifh.t Linq2Objects delen som der er i dag.

  • Parallel Extensions er et bud på at lave en programmeringsmodel der understøtter multi-core og CPU programmering.

Page 1 of 1 (4 items)