using System; namespace _15_Delegates; // C# hat für Lambda-Ausdrücke und Methodenreferenzen ein eigenes Konzept: Die Delegates. // Das Prinzip dahinter ist ähnlich den "functional Interfaces". public delegate int Vergleich(int a, int b); // Hier erstellen wir einen neuen Datentypen 'Vergleich', welcher nun int-Methoden mit zwei int-Parametern annehmen kann. Einer Variable dieses Datentyps können wir alle Methoden zuweisen, deren Methodensignatur zum Delegaten passt. Für die Signatur ist wichtig: Rückgabetyp und Parametertypen und -anzahl. internal class Delegates { public static void Main(string[] args) { // Mit dem Delegate-Datentypen erzeugen wir eine Variable, der wir einen Lambda-Ausdruck zuweisen. // Der Lambda-Ausdruck ist hier eine anonyme Methode, die festlegt, wie die Sortierreihenfolge eines Sortieralgorithmus sein soll. // Siehe: CompareTo()-Methode Vergleich v = (x, y) => { if (x > y) return 1; else if (y > x) return -1; else return 0; }; int[] array = { 9, 1, 8, 2, 7, 3, 6, 4, 5 }; BubbleSort(array, v); Console.WriteLine(String.Join(", ", array)); // Vordefinierte Delegates in C# sind unter anderem: Action action; // Void-Methode mit bis zu 16 Parametern. (Vergleich zum Consumer in Java) Func func; // Methode mit beliebigem Return-Typ und bis zu 16 Parametern. (Vergleich zum Function-Interface in Java) Predicate predicate; // Boolean-Methode mit einem Parameter. (Wie Predicate in Java) Comparison comparison; // Integer-Methode mit zwei Parametern vom selben Typ. (Wie Comparator in Java) EventHandler eventHandler; // Wird für Events verwendet (Observer Pattern). // Beispiel für Events: Button b = new Button(); b.Text = "Ich bin ein Button"; b.OnClick += ButtonClicked; // Das Event wird durch += abonniert. Hier wird dem Delegaten die Referenz auf die ButtonClicked()-Methode zugewiesen. b.OnClick += ButtonClicked; b.OnClick -= ButtonClicked; // Mit -= können Events wieder de-abonniert werden. b.OnClick += (s, e) => Console.WriteLine("Über Lambda-Ausdruck"); b.Click(); // Auf den Button klicken... // Multicast: Action a; a = Console.WriteLine; a += (s) => Console.WriteLine(s.ToUpper()); a += (s) => Console.WriteLine(s.Substring(0, s.Length / 2)); a.Invoke("Hallo, Welt!"); // Alle zugewiesenen Methoden werden nacheinander aufgerufen. Delegate[] invocationList = a.GetInvocationList(); invocationList[1].DynamicInvoke("Dynamisch aufgerufen"); } //Ein Sortieralgorithmus, bei dem durch Übergabe des Delegates bestimmt wird, wie sortiert werden soll (Aufsteigend oder Absteigend) public static void BubbleSort(int[] array, Vergleich vergleich) { if (vergleich == null) // Wir prüfen zuerst, ob überhaupt eine Methode übergeben wurde... return; for (int i = 0; i < array.Length; i++) { for (int j = 0; j < array.Length - 1 - i; j++) { if (vergleich(array[j], array[j + 1]) == 1) // Aufruf der Methode im Delegate. Dazu können wir den Delegate wie eine Methode verwenden. { // Zwei Elemente tauschen: /*int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp;*/ // Der Tausch von zwei Variablen in einem Schritt über Tupel: (array[j], array[j + 1]) = (array[j + 1], array[j]); } } } } // EventHandler-Methode: Diese muss zur Signatur des EventHandler-Delegaten passen. public static void ButtonClicked(object? sender, EventArgs e) { Console.WriteLine((sender as Button)?.Text); Console.WriteLine("Der Klick wurde verarbeitet..."); } }