Lambda expressies
Lambda expressies zijn niets nieuws. De eerste publicatie over 'lambda calculus'
dateert uit de jaren dertig, dat is dus ver voordat men na begon te denken over
C#. Lambda expressies vormen een belangrijk onderdeel van de taal Lisp maar zijn
ook in andere omgevingen terug te vinden. Voor een overzicht van de Lambda calculus,
zie
deze entry in Wikipedia. Voor ons is het genoeg om te weten dat een Lambda expressie
een andere schrijfwijze voor een functie is. Ik zal een voorbeeld geven:
Neem de wiskundige functie die een getal met zichzelf vermenigvuldigt: f(x) =
x * x. In de lambda notatie wordt dat ? x. x * x. In C# drukken
we dat uit als (int
x) => x * x;
Let op: dit is geen compileerbare code, dit is slechts een schrijfwijze van een
functie!
Een ander voorbeeld is bijvoorbeeld een functie die twee doubles bij elkaar optelt
en het resultaat teruggeeft:
(double
x, double y) => return
x + y;
We kunnen deze schrijfwijze gebruiken om de anonymous methods uit C# 2.0 te vereenvoudigen.
Neem bijvoorbeeld de method List.FindAll(). Deze method ziet er als volgt uit:
public
List List.FindAll(Predicate
match) { ... }
De Predicate staat voor een delegate:
public
delegate bool
Predicate(T obj);
In het kort komt dit dus op het volgende neer: aan FindAll geef je een delegate
mee, welke wordt aangeroepen voor ieder item T in de List. In de delegate kijk
je of het meegegeven item voldoet aan een bepaalde eis, en je geeft true of false
terug, al naar gelang de uitkomst. Hoewel deze functionaliteit nieuw is in C# 2.0,
zal ik eerst even laten zien hoe je hem zou moeten gebruiken zonder anonymous methods:
List<string>
lijst = new List<string>
{ "Dit", "is",
"een", "verzameling",
"strings" };
List<string>
newLijst = lijst.FindAll(ValidateString);
foreach(
string s in newLijst
) {
Console.WriteLine(s);
}
De delegate ValidateString ziet er als volgt uit:
public
static bool ValidateString(string
s) {
return (s.Length > 3);
}
Met andere woorden: we lopen door een lijst van strings heen, en geven een subset
daaruit terug, bestaande uit strings met een lengte van meer dan 3. Het resultaat
zal dan ook zijn "verzameling" en "strings".
In C#2.0 hebben we anonymous methods. Dit betekent dat we bovenstaande code kunnen
schrijven zonder de ValidateString() method te maken. Dat gaat als volgt:
List<string>
lijst = new List<string>
{ "Dit", "is",
"een", "verzameling",
"strings" };
List<string>
newLijst = lijst.FindAll(delegate(string
s) { return (s.Length > 3);});
foreach(
string s in newLijst
) {
Console.WriteLine( s );
}
Zoals je ziet hebben we de delegate niet meer nodig: de code daarvoor staat in
de lijst.Findall() aanroep. Uiteraard is dit alleen handig indien de code in de
delegate niet al te groot is; anders kun je beter een aparte method gebruiken.
In C# 3.0 kunnen we dit nog vereenvoudigen, met behulp van type inferrence en
lambda expressions:
var lijst
= new List<string>
{ "Dit", "is",
"een", "verzameling",
"strings" };
var newLijst =
lijst.FindAll((string s) => (s.Length > 3));
foreach(
var s in newLijst
) {
Console.WriteLine( s );
}
Door het gebruik van het 'var' keyword en de lambda expressie(string
s) => (s.Length > 3)is de code een stuk overzichtelijker geworden.
Dit is voorlopig de laatste posting over de nieuwe features in de taal C# 3.0.
Volgende keer zal ik alles wat ik in de afgelopen 5 postings gedemonstreerd heb
samenvoegen in een overzicht van Linq.
Even in het kort: Linq staat voor Language Integrated Query, een manier om queries
op te bouwen in je C# code. Dit is mogelijk doordat C# uitgebreid is met alle mogelijkheden
die ik tot nu toe heb laten zien.
Dus als je je afvraagt waar dit hele verhaal naar toe gaat, hou mijn blog in
de gaten en zie het allemaal samen komen in mijn bespreking van Linq, DLinq en XLing!