C# 3.0: Lambda Ausdrücke

C# 3.0: Lambda Ausdrücke

Seit Version 3.0 von C# gibt es als Alternative zu anonymen Methoden Lambda Ausdrücke, die insbesondere eine kompaktere Syntax ermöglichen, jedoch keine erweiterte Funktionalität bieten.

Ein Lambda Ausdruck ist ein Ausdruck, der zu einer Funktion evaluiert wird, mit dieser Funktion läßt sich alles machen, was sich auch mit normalen Funktionen machen läßt.

Insbesondere werden Lambda Ausdrücke  benutzt, um Delegates zu benutzen. Es lassen sich jedoch zahlreiche Anwendungen finden, inkl. eines direkten Aufrufes von definierten Lambda Ausdrücken, auch sehr nützlich ist die Benutzung in ForEach Aufrufen oder in anderen Funktionen, die weitere Funktionen als Parameter zulassen oder als Adapter zum Anpassen der Signatur einer vorhandenen Funktion auf eine Zielsignatur (z. B. bei Events).

Anbei eine C#-Windows-Konsolenanwendung mit zugehöriger Ausgabe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace LambdaTest
{
    class Program
    {
        // Delegates und Funktionen werden weiter unten verwendet
        delegate void DoWithString(string s);
        delegate void DoWithTime(TimeSpan t);
        delegate int UsingRef(ref int n);
        // Funktion muß statisch sein, da sie aus dem statischen Main aufgerufen wird
        public static void DoWithHours(int hours)
        {
            Console.WriteLine("Stunden vergangen: " + hours);
        }
        class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public Person(string FirstName, string LastName)
            {
                this.FirstName = FirstName;
                this.LastName = LastName;
            }
            public override string ToString()
            {
                return FirstName + " " + LastName;
            }
        }
 
        static void Main(string[] args)
        {
            // *** *** hier beginnen die Beispiele *** ***
            // einfache Funktionsdefinitionen und Aufrufe
            Console.WriteLine("---*** Einfache Beispiele ***---");
            Func<int,int> square = x => x * x;
            Console.WriteLine("Quadrat von 3: " + square(3));
 
            // alternative Syntax
            square = (int x) => x * x;
            square = x => x * x;
            square = x => { return x * x; };
            Console.WriteLine("Quadrat von 4: " + square(4));
 
            // ohne Eingabeparameter
            Func<double> ReturnDouble;
            ReturnDouble = ()=>3.1415;
            Console.WriteLine("Pi ist: " + ReturnDouble());
 
            // 2 Eingabeparameter und Rückgabewert (2 Eingabeprameter erfordern link ( ) )
            Func<int, int, int> TwoParam;
            TwoParam = (x, y) => x * y;
            // mehrere Anweisungen erfordern rechts { }
            TwoParam = (x, y) => { ++x; ++y; return x * y; };
            Console.WriteLine("Ergebnis ist: " + TwoParam(3,4));
 
            Action<string> greet = (string x) => { Console.WriteLine("Hallo " + x + "."); };
            greet("Peter");
 
            DoWithString myGreeting = x => { string str = x + " ist nett."; Console.WriteLine(str); };
            myGreeting("Bill");
 
            // Zugriff auf externe (z. B. lokale) Variablen (im Scope des Lambda Ausdruckes)
            for (int i = 5; i < 7; ++i)
            {
                Action<string> tell = (string x) => { Console.WriteLine("{0} hat {1} Freunde", x, i); };
                tell((i==5)?"Rudi":"Peter");
            }
 
            Console.WriteLine("---*** Lambda und Listen ***---");
            // Benutzung von Lambda Ausdrücken auf Listen etc.
            List<object> list = new List<object>() { 1, 2, 3, "Pferd", "Tier" };
            list.ForEach(s => Console.WriteLine(s));
 
            // eine Lambda Funktion direkt evaluieren (mit und ohne Cast nach Delegate)
            int n1 = ((Func<int, int>)(delegate(int n) { return n * n; }))(3);
            int n2 = ((Func<int, int>)(n => n * n))(4);
            int twelve = ((Func<int, int, int>)((a, b) => a *b))(3, 4);
            Console.WriteLine("{0}, {1}, {2}", n1, n2, twelve);
 
            // ein Referenzparameter (ref) verändert auch den ursprünglichen Parameter
            int n3 = 3;
            // kompiliert nicht, hier kann ein Func nicht benutzt werden
            //int n4 = ((Func<ref int, int>)((ref int n)=> ++n))(n3);
            UsingRef ur = (ref int n) => ++n;
            int n4 = ur(ref n3);
            Console.WriteLine("Mit Referenz: {0}, {1}", n3, n4);
 
            Console.WriteLine("---*** noch mehr Lambda ***---");
            int[] numbers = { 1, 6, 32, 1, 9, 77 };
            int numOddNumbers = numbers.Count(n => n % 2 == 1);
            Console.WriteLine(numOddNumbers + " ungerade Zahlen.");
 
            var numbersLessThan10 = numbers.TakeWhile(n => n < 10);
            numbersLessThan10.ToList().ForEach( n => Console.Write(n + " ") );
            // wir erhalten alle Zahlen von Anfang an, bis eine Zahl >= 10 angetroffen wird
            Console.WriteLine("sind die Zahlen kleiner 10.");
 
            // anonyme Operatoren mit yield und Lambda Audruck funktionieren leider nicht
            //IEnumerable<int> twoints = ()=>{ yield return x; yield return x*10; };
            //foreach(int i in twoints) ...
            // s. a. http://blogs.msdn.com/b/ericlippert/archive/2009/08/24/iterator-blocks-part-seven-why-no-anonymous-iterators.aspx
 
            // Parameter verändern nach dem Adapter-Pattern
            DoWithTime f_t = t => DoWithHours(t.Hours);
            f_t(new TimeSpan(10, 100, 10));
            // typischerweise wird dies z. B. bei vorgegebener Signatur bei Events verwendet
 
            // Auswahl/Konvertierung für Parameter per Lambda Ausdruck
            List<person> people = new List<person>
            (new[] {
                new Person("Bill", "Gates"),
                new Person("Barack", "Obama"),
                new Person("Angela", "Merkel"),
                new Person("Zoo", "Lander")
            });
            // sehr kompakte Syntax
            people = people.OrderBy(x => x.FirstName).ToList();
            people.ForEach(s => Console.WriteLine(s));
 
            Console.ReadLine();
        }
    }
}

und die zugehörige Ausgabe


---*** Einfache Beispiele
---*** Einfache Beispiele ***---
Quadrat von 3: 9
Quadrat von 4: 16
Pi ist: 3,1415
Ergebnis ist: 20
Hallo Peter.
Bill ist nett.
Rudi hat 5 Freunde
Peter hat 6 Freunde
---*** Lambda und Listen ***---
1
2
3
Pferd
Tier
9, 16, 12
Mit Referenz: 4, 4
---*** noch mehr Lambda ***---
4 ungerade Zahlen.
1 6 sind die Zahlen kleiner 10.
Stunden vergangen: 11
Angela Merkel
Barack Obama
Bill Gates
Zoo Lander

Gedacht ist dies als Referenz/Ansammlung einer ganzen Reihe von Möglichkeiten, mit Lambda Ausdrücken umzugehen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.