22 Gäste und 0 Benutzer online | Anmelden | Registrieren


Designelement Startseite

Designelement Windows-Artikel
  Designelement Problemlösungen
  Designelement Einstellungen
  Designelement Anleitungen
  Designelement Hardware
  Designelement FAQ
  Designelement C#.NET

Designelement Forum
Designelement Gästebuch

Designelement Programme
  Designelement Onlinetools
  Designelement Downloads

Designelement Suche
Designelement Links

Designelement Impressum
Designelement Kontakt

Designelement Anmelden





Zu den C#.NET-Artikeln

  Delegates als Platzhalter für Funktionen - C#
Am 02.12.2007 verfasst von Andreas Nägeli. Hits: 1118

Delegates können als Platzhalter für Funktionen in Objekten verwendet werden. Wenn die Delegatefunktion aufgerufen wird, werden alle hinterlegten Funktionen (in der Reihenfolge in der sie hinzugefügt wurden) ausgeführt.

Dies ist sehr praktisch, wenn Sie eine Nachricht an ein Objekt schicken müssen, dessen Aufbau Sie nicht kennen. Dies ist zum Beispiel bei Klassenbibliotheken häufig der Fall.

Um dies etwas anschaulicher erklären zu können, behelfe ich mich eines kleinen Beispiels:

public delegate void gotData(Server svr, String Data);

public class Server {
  public gotData ongotData;

  public void Run() {
    // ...
    for (int i = 0; i < 5; i++) {
      Thread.Sleep(new Random().Next(250));
      if (ongotData != null)
        ongotData(this, "SomeData");
    }
    // ...
  }

  public void sendData(String Data) {
    // ...
    Console.WriteLine("sent data: " + Data);
  }
  
}


Dieses Beispiel soll einen Server simulieren, der in unregelmäßigen Abständen Daten von einem verbundenen Client empfängt. Dies schließt zunächst aus, dass die Funktion Run() die empfangenen Daten als String zurückgibt. Schließlich müssen wir in Echtzeit auf die ankommenden Daten reagieren können.

Wir könnten statt dessen ein Objekt übergeben, und beim Empfang von Daten eine Funktion wie object.gotData() aufrufen. Dies würde allerdings vorraussetzen, dass die Serverklasse Kenntnis vom Aufbau des Objektes haben müsste. Da dies nur über Interfaces allgemeingültig zu regeln wäre, würde es verhältnismäßig viel Aufwand für uns bedeuten.

Stattdessen definieren wir einfach eine Funktion, die wir immmer aufrufen können, wenn wir Daten empfangen haben. Diese Funktion "zeigt" zunächst ins Leere, kann aber von Objekten, die Daten empfangen möchten, auf eigene Funktionen umgelenkt werden.

Solch ein Delegate definieren wir in unserem Beispiel. Die Syntax für die Definition lautet wie folgt:

Modifier delegate Rückgabetyp Delegatename(Übergabeparameter)

in unserem Beispiel

public delegate void gotData(Server svr, String Data);


Dies ist die Definition, die wir im folgenden wie einen Typ verwenden können. In der Klasse Server selbst haben wir solch ein Objekt des Typs gotData erstellt.

Wenn nun die Funktion Run() von einem Objekt aufgerufen wird und Daten eintreffen (hier simuliert durch eine verzögerte for-Schleife), führen wir die stellvertretende Delegatefunktion ongotData aus, die alle hinterlegten Funktionen bedient.

Nun müssen wir die Server-Klasse nur noch anwenden können.

public class Program {

  static void Main(string[] args) {
    Server svr = new Server();
    svr.ongotData = new gotData(gotDisplayData);
    svr.ongotData += new gotData(gotProtokollData);
    svr.Run();
  }

  private static void gotDisplayData(Server svr, String Data) {
    Console.WriteLine("got data: " + Data);
  }

  private static void gotProtokollData(Server svr, String Data) {
    svr.sendData("SomeMoreData");
  }

}


Im Beispiel möchten wir gleich zwei Rückmeldefunktionen verwenden, die dann aufgerufen werden, wenn Daten empfangen werden. gotDisplayData soll die empfangenen Daten nur auf der Konsole ausgeben, während gotProtokollData auch entsprechend auf die eingegangenen Daten reagieren soll.

Bevor wir die Run-Methode ausführen, müssen wir dem Server-Objekt eigentlich nur noch sagen, welche Funktionen es ausführen soll, wenn gotData vom Server aufgerufen wird. Dazu fügen wir gotData zwei neue Verweise auf die bereits implementieren Funktionen an.

Wenn wir das Testprogramm nun ausführen, werden in unregelmäßigen Abständen Daten empfangen und anschließend gleich versendet. Selbstverständlich hätte man hier auch die statische Program-Klasse übergeben können, aber dies ist weitaus unflexibler als der Weg über den Delegate. Würde man die Severklasse noch mit einem anderen Objekt verwenden wollen, so müsste man den Server selbst ändern. Über Delegates ist die aufgerufene Klasse unabhängig von der Ausführenden.

Sie sollten beachten, dass oben beim Hinzufügen der Delegatefunktionen beim zweiten Mal der Operator += und nicht = verwendet wurde. Dies ist deshalb der Fall, weil wir eine weitere Funktion hinzufügen, und eben nicht die vorhandene Liste überschreiben möchten. Mit -= können Sie Funktionen auch wieder aus der Liste entfernen.

Wichtig ist auch, dass es in C# keine Singlecast-Delegates gibt, sondern dass immer eine Liste (Multicast) von Funktionen hinterlegt wird.

Kommentiertes Codebeispiel herunterladen (CLDelegates.rar, 16 KB, VS80)

Bewertung dieses Artikels von 4 Benutzern: Mit 3 von 10 Punkten bewertet - 3.25 / 10 Punkte

Wie finden Sie diesen Artikel?











  2002 - 2008 Designelement Computerleben.net Designelement Sitemap