Weniger Ballast – Anonymous Methods
Die zuvor gezeigten Beispiele verdeutlichten die Arbeitsweise von Funktionszeigern mit benannten Methoden. Die generelle Anlage einer separaten Methode, die durch den Delegate aufgerufen werden soll, wirkt sich aber teilweise negativ auf die Qualität des Quellcodes aus. Die Implementierung in Listing 3 ist dafür ein typisches Beispiel. Betrachtet man die Anweisung List
static List<int> arr = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20 };public static void Test(){List<int> result = arr.FindAll(delegate(int figure){return (figure % 2) == 0;});}
Listing 5
Eingeleitet wird die anonyme Methode mit dem Schlüsselwort delegate, gefolgt von – wenn vorhanden – Parametern. Wie hier erkennbar ist, können auch generische Parameter verwendet werden. Im anschließenden Codeblock wird die nötige Logik hinterlegt. Durch die Verwendung einer anonymen Methode wird der Quellcode lesbarer. Nun ist sofort ersichtlich, welche Zahlen von dem Aufruf zurückgeliefert werden. Anonyme Methoden können an vielen Stellen des .NET Frameworks verwendet werden. Innerhalb einer WinForms-Anwendung kann z. B. das Klickereignis auf einer Schaltfläche durch eine anonyme Methode behandelt werden:
btnCancel.Click += delegate(object sender,EventArgs args)
{ MessageBox.Show("Abbruch"); };
Weitere Beispiele und Erläuterungen sind unter [2] abrufbar.
Interne Funktionsweise
Je nachdem, welche Parameter und Variablen eine anonyme Methode verwendet, variiert der Code, der vom Compiler erzeugt wird. Eine anonyme Methode kann lokale Variablen nutzen, solche, die über Parameter übergeben wurden, oder auch global verfügbare Variablen. Im einfachsten Fall verwendet die anonyme Methode nur interne Variablen. Listing 6 zeigt dazu eine entsprechende anonyme Methode. In diesem Fall fügt der Compiler während der Übersetzungszeit der Klasse eine neue private Methode mit folgender Signatur hinzu: [Rückgabetyp] [Äußeren Methodennamen][Eindeutigen Namen]_[Anzahl Parameter].
delegate void CallBack();public static void Listing6(){CallBack cb = delegate(){ Console.WriteLine("Hello"); };cb();}
Listing 6
Listing 7 zeigt den vollständigen MSIL-Code der erzeugten privaten Methode.
.method private hidebysig static void <Listing6>b__0() cil managed{.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor().maxstack 8L_0000: ldstr "Hello"L_0005: call void [mscorlib]System.Console::WriteLine(string)L_000a: ret}
Listing 7
Dann ermittelt der Compiler mittels Delegate Inference den Typ des Delegaten, legt diesen an und übergibt den Namen der neu erzeugten privaten Methode. Verwendet die anonyme Methode darüber hinaus äußere Variablen, wird der erzeugte MSIL-Code komplexer. Hierbei muss der Compiler zunächst eine neue interne Klasse anlegen, in der dann wiederum die neue Methode angelegt wird. Wie aus der Beschreibung erkennbar wird, vervollständigt der Compiler automatisch die „fehlenden“ Implementierungen. Aus Sicht des MSIL-Codes existieren daher eigentlich keine anonymen Methoden.
Zusammenfassung
Anonyme Methoden können helfen, den Quellcode übersichtlicher und strukturierter zu organisieren. Sie sollten aber wirklich nur dann verwendet werden, wenn die Methode nur einmalig benötigt wird. Sobald die Methode an mehreren Stellen aufgerufen werden muss, darf – gemäß dem DRY-(Don’t-Repeat-Yourself-)Prinzip – keine anonyme Methode verwendet werden. In diesem Fall muss zwingend eine benannte Methode implementiert werden.



