Dennis' Blog

Avonturen in .NET
posts - 37, comments - 633, trackbacks - 0, articles - 0

Sunday, October 09, 2005

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!

posted @ 8:21 PM | Feedback (24)