Site logo
Site logo
Programmieren aus Leidenschaft
Programmieren aus Leidenschaft

Delegates mal ganz einfach


Oft wurde ich gefragt, wie das in C# mit den Delegates funktioniert. Ist man andere Programmiersprachen gewöhnt, können Delegates zu Anfang etwas verwirrend sein, obwohl es eine einfache und durchaus nützliche Technik ist. Leider sind die meisten Beispiele in der Literatur etwas zu komplex um schnell verstanden werden zu können. Darum machen wir es hier jetzt ganz einfach.

private delegate void aufruf(string s, string x);

Hier wird ein Delegate mit dem Namen "aufruf" erzeugt. Das ganze ist einer Methodendeklaration nicht unähnlich. Es gibt zwei Parameter, nämlich s und x, beide vom Typ "string". Einen Rückgabewert haben wir in diesem Beispiel nicht, unsere delegate ist void. Natürlich kann ein Delegate auch einen Wert zurück geben, hier aber eben nicht. Was diese Deklaration von einer Methode unterscheidet, ist nicht nur das Wort "delegate", sondern auch der fehlende Programmcode den eine Methode ausführt. Das ist nicht weiter verwunderlich denn Delegates sind keine Methoden sondern Methodenverweise. Wenn man also ein Delegate erzeugt, so ist das ein Objekt, das einen Verweis für eine Methode aufnehmen kann.
Erzeugen wir also zwei Methoden.

private void m1(string str1, string str2)
{
   MessageBox.Show(str1 + " " + str2);
}

private void m2(string str1, string str2)
{
   MessageBox.Show(str2 + " " + str1);
}


Was diese zwei Methoden tun ist sicherlich schnell zu verstehen. Viel wichtiger ist aber, dass beide Methoden die gleichen Parameter haben wie der Delegate, nämlich zwei Parameter vom Typ "string". Also kann der Delegate als Verweis für diese Methoden verwendet werden.

aufruf myAufruf1 = new aufruf(m1);
myAufruf1("Hallo", "Welt");


Zuerst wird ein neues Objekt des Delegates "aufruf" erzeugt. Als Parameter bekommt der Delegate die Methode "m1", die hier ohne ihre eigenen Parameter verwendet wird. Das ist auch nicht nötig. Durch die Deklaration des Delegate wird festgelegt, dass man nur auf Methoden verweisen kann, die zwei mal den Typ "string" erwarten. Die zweite Programmzeile führt die Methode aus und "Hallo Welt" wird in einem Fenster angezeigt.

aufruf myAufruf2 = new aufruf(m2);
myAufruf2("Hallo", "Welt");


In diesem Beispiel wird ein Verweis auf die Methode "m2" angelegt, die bei Ausführung dann "Welt Hallo" ausgibt.

Multicasting Delegates
Eines der nützlichsten Merkmale von Delegates ist die Fähigkeit durch so genanntes "Multicasting" komplexe Ereignisketten zu bilden, die dann durch einen einzigen Aufruf abgearbeitet werden. Hierbei beziehe ich mich wieder auf die Delegates und Methoden aus dem letzen Beispiel.

aufruf myAufruf;
aufruf myAufrufTeil1 = new aufruf(m1);
aufruf myAufrufTeil2 = new aufruf(m2);


Zuerst werden drei Verweisobjekte erzeugt. Im Unterschied zum ersten Beispiel enthält "myAufruf" aber noch keinen Verweis. "myAufruf1" und "myAufruf2" hingegen schon. Warum das so ist wird klar, wenn man die nachfolgenden Programmzeilen sieht.

myAufruf = myAufrufTeil1;
myAufruf += myAufrufTeil2;


Zuerst bekommt "myAufruf" den Verweis von "myAufruf1". In der zweiten Zeile wird dann durch die Verwendung von "+=" eine zweite Methode "angehängt".

myAufruf("Hallo", "Welt");

In dieser Zeile werden beide Methoden letztendlich aufgerufen. Zuerst wird "Hallo Welt" und anschließend automatisch auch "Welt Hallo" ausgegeben.
Dies mag schon ein eindrucksvolles Beispiel sein aber es wird sicher schnell die Frage aufkommen, ob die Methoden nicht auch die Parameter verändern können, bevor sie diese an die nachfolgenden Methoden weitergeben. Wie das nachfolgende Beispiel zeigt, ist auch das möglich.


Multicasting Delegates mir Referenzen
In den letzen beiden Beispielen wurden immer Parameter vom Typ "string" an Methoden, bzw. an Delegate übergeben. Zwar wurden diese Werte in den Methoden nie geändert aber selbst wenn die Werte manipuliert worden wären, so wären diese Änderungen ausschließlich innerhalb der Methode wirksam. Einfach ausgedrückt macht sich die Methode Kopien von den Parameterwerten, die übergeben werden. Manchmal kann es aber wünschenswert sein, dass eine Methode die übertragenen Parameter nach Änderung zurückgibt. In solch einem Fall muß man mit Referenzen arbeiten. Zwar können Methoden auch durch den "return" Befehl einen Wert zurück geben, aber eben nur einen Einzigen.
Für den Delegate bedeutet das nun, dass er keine Parameter vom Typ "string" mehr entgegen nimmt, sondern Referenzen auf einen solchen Typ.

delegate void aufrufByRef(ref string a, ref string b);

Genauso verhält es sich dann mit den Methoden. Anders als in den vorherigen Beispielen kommen hier aber Methoden zum Einsatz, welche die übergebenen Parameter auch verändern. Die Methode "r1" ersetzt alle Buchstaben "l" durch die Ziffer "7", während Methode "r2" alle Buchstaben in Großbuchstaben verwandelt.

private void r1(ref string x1, ref string x2)
{
   x1 = x1.Replace("l", "7");
   x2 = x2.Replace("l", "7");
   MessageBox.Show(x1 + " " + x2);
}

private void r2(ref string x1, ref string x2)
{
   x1 = x1.ToUpper();
   x2 = x2.ToUpper();
   MessageBox.Show(x1 + " " + x2);
}


Der Aufruf des Delegate sollte aus dem letzten Beispiel bekannt sein.

aufrufByRef myAufruf;
aufrufByRef myAufruf1 = new aufrufByRef(r1);
aufrufByRef myAufruf2 = new aufrufByRef(r2);

myAufruf = myAufruf1;
myAufruf += myAufruf2;

string a = "Hallo";
string b = "Welt";

myAufruf(ref a, ref b);


Wird nun dieses Programm ausgeführt, so wird durch den Aufruf der ersten Methode "Ha77o We7t" ausgegeben, da alle Buchstaben "l" ersetzt wurden. Anschließend werden die so veränderten Werte an die nächste Methode weitergereicht die damit "HA77O WE7T" ausgibt.

Es gibt hier noch ein wichtiges Merkmal: Da mit Referenzen gearbeitet wird können nicht direkt Zeichenketten an die Methoden bzw. die Delegate übergeben werden. Der Text muß vorher in Variablen gespeichert werden (hier "a" und "b"). Denn es sind diese Variablen, die durch die Referenzen geändert werden.

Delegates sind ein nützliches Element zur modularen Programmierung und sie sind wichtig wenn man mit Ereignissen (Events) arbeiten will. Aber das ist ein anderes Thema.