Delegatesund Ereignisse «Delegierter» Methoden Schablone Funktionszeiger Dr. Beatrice Amrhein
Überblick Definition eines Delegat Einfache Delegate Beispiele von Delegat-Anwendungen Definition eines Ereignisses Einfache Ereignisse Beispiele von Ereignissen 2
Definition 3
Definition Ein Delegat ist ein Typ, der eine Referenz (Zeiger) auf eine Methode beschreibt. Delegate entsprechen den Funktionszeigern in C++, sie sind jedoch typsicher und geschützt. Delegate ermöglichen es, Methoden als Parameter zu übergeben. Delegate können miteinander verkettet werden (nacheinander ausgeführt). 4
Hinweis Delegate bilden die Grundlage für Ereignisse (wie z.b. für Benutzer-Eingaben). Durch das Verketten von Delegaten können mehrere Methoden an ein Ereignis angebunden werden. Alle miteinander verketteten Delegate werden gemeinsam (nacheinander) aufgerufen. 5
Deklaration Die Deklaration von einem Delegat sieht ähnlich aus wie eine Methodensignatur. Sie benötigt das Schlüsselwort delegate Sie hat einen Rückgabewert und eine beliebige Anzahl Parameter: <sichtbarkeit> delegate <Resultat-Typ> <Delegat-Name> (<Parameter-Liste>) Zwei Beispiele: public delegate void meindelegat1(int n, string message); public delegate int meindelegat2(object m, double d); 6
Benutzen von Delegates Der Einsatz von Delegates erfolgt in drei Schritten. 1. Deklaration des Delegate public delegate int meindelegate( string s, int i ) 2. Definieren des Delegate-Objekt mit der entsprechenden Methode meindelegate delegatename = methode; 3. Aufruf des Delegate-Objekts und dadurch indirekter Aufruf der Methode int resultat = delegatename("eingabe", 17); 7
Erstes einfaches Beispiel: Verschiedene Ausgabe- Funktionen 8
Ein C# Beispiel: Die Klasse Ausgabe Die Klasse Ausgabe hat zwei verschiedene Methoden zum Schreiben (auf die Konsole und in eine Datei) mit gleicher Signatur. using System; using System.IO; class Ausgabe // Schreiben auf die Konsole public static void WriteToScreen(string str) Console.WriteLine("Ausgabe: 0", str); //Schreiben in die Datei Test.txt const string filename = "C:\\tmp\\Test.txt"; public static void WriteToFile(string s) File.AppendAllText(fileName, s); 9
Ein C# Beispiel: Die Klasse Ausgabe // Deklaration des Delegaten mit gleicher Signatur // wie die beiden Methoden WriteToScreen und WriteToFile) public delegate void SchreibeDelegate(string s); 10
Ein C# Beispiel: Das Hauptprogramm //Benutze die Delegates static void Main(string[] args) SchreibeDelegate psdelegate; string text = "Hier ist mein Text für dieses Beispiel"; //Zuweisen und ausführen der Methode «Schreibe auf den Schirm» psdelegate = WriteToScreen; psdelegate(text); // Zuweisen und ausführen der Methode «Schreibe ins File» psdelegate = WriteToFile; psdelegate(text); 11
Zweites Beispiel Rechner 12
Ein C# Beispiel: Die Klasse Rechner Die Klasse Rechner hat vier verschiedene Rechnungs-Methoden mit gleicher Signatur. class Rechner public static double Addition(double x, double y) return x + y; public static double Subtraktion(double x, double y) return x - y; public static double Multiplikation(double x, double y) return x * y; public static double Division(double x, double y) return x / y; 13
Ein C# Beispiel: Das Hauptprogramm // Deklaration des Delegate gleiche Signatur wie die Methoden von Rechner public delegate double RechnungsOperation(double d1, double d2); class Program static void Main(string[] args) // Initialisierung des Delegats RechnungsEinheit berechne = Rechner.Addition; do // Einlesen der Operation Console.Write("Operation: +, -, * oder / "); char wahl = Console.ReadLine()[0]; 14
Ein C# Beispiel: Das Hauptprogramm // Zuweisen der ausgewählten Operation der richtigen Methode switch (wahl) case '+': berechne = Rechner.Addition; break; case '-': berechne = Rechner.Subtraktion; break; case '*': berechne = Rechner.Multiplikation; break; case '/': berechne = Rechner.Division; break; 15
Ein C# Beispiel: Das Hauptprogramm // Aufruf der Operation '+', '-', '*' oder '/' über das Delegat double resultat = berechne(input1, input2); // Ausgabe des Resultats Rechner.Ausgabe(wahl, x, y, resultat); Console.WriteLine("Beenden mit q, weiter mit w: "); while (Console.ReadLine()!= "q"); 16
Verwenden von Delegaten als Parameter 17
Ein C# Beispiel: Die Methode Ausgabe Wir wählen nochmals das ursprüngliche Delegat RechnungsOperation: public delegate double RechnungsOperation(double d1, double d2); Die Methode Ausgabe hat als vierten Parameter eine Rechnungs- Operation (also ein Delegat) public static void Ausgabe(double d1, double d2, char c,... RechnungsOperation berechne) 18
Ein C# Beispiel: Die Methode Ausgabe Die so übergebene Funktion kann dann innerhalb der Methode verwendet werden: public static void Ausgabe(double d1, double d2, char c, Console.WriteLine("0 1 2 = 3\n", RechnungsOperation berechne) d1, c, d2, berechne(d1, d2)); 19
Ereignisse 20
Definition Events oder Ereignisse dienen dazu, Informationen über eingetretene Benutzer-Eingaben oder Daten-Änderungen an andere Klassen oder Objekte zu übermitteln. Die Klasse, die das Ereignis sendet (oder auslöst), wird als Herausgeber (Publisher) bezeichnet Die Klassen, welche das Ereignis empfangen (oder behandeln), werden als Abonnenten (Subscriber) bezeichnet. 21
Definition Das abstrakte Modell 22
Eigenschaften Der Herausgeber bestimmt, wann ein Ereignis ausgelöst wird. Die Abonnenten bestimmen (durch ihre Event-Methoden), wie auf ein Ereignis reagiert werden soll. Ein Ereignis kann mehrere Abonnenten haben. Die Anmeldung geschieht über += Ein Abonnent kann sich wieder abmelden durch -= Ein Abonnent kann mehrere Ereignisse von verschiedenen Herausgebern behandeln. Ereignisse, die keine Abonnenten haben, werden unterdrückt (nicht ausgelöst). 23
Eigenschaften Ereignisse dienen normalerweise zur Signalisierung von Benutzeraktionen wie das Klicken auf Schaltflächen oder Auswählen von Menüs in der grafischen Benutzeroberfläche. Wenn ein Ereignis mehrere Abonnenten hat, werden die Ereignis-Methoden aller Abonnenten (nacheinander) aufgerufen. Ereignisse basieren auf Delegaten Sie benutzen die C#-Klasse EventArgs (Ereignis-Argumente) zum Übergeben von Informationen. 24
Ein einfaches Beispiel 25
Ein C# Beispiel: Die Klasse Herausgeber public class Herausgeber // Definiere ein Delegat und eine EreignisBehandler Liste public delegate void EreignisDelegat(EreignisArgument s); public event EreignisDelegat ereignisbehandler; // Anmelden einer Ereignis-Methode public void Registriere(EreignisDelegat s) ereignisbehandler += s; // Publiziere ein Ereignis. public void publiziere(string m) EreignisArgument ea = new EreignisArgument(m); ereignisbehandler(ea); 26
Ein C# Beispiel: Die Klasse Abonnent Die Klasse Abonnent habe zwei Methoden, welche die Methoden-Schablone (Delegat) erfüllen. public class Abonnent public void EventMethode1(EreignisArgument s) Console.WriteLine(s.meldung + " ist angekommen"); public void EventMethode2(EreignisArgument s) Console.WriteLine(s.meldung + " wird behandelt"); public class EreignisArgument : EventArgs public string meldung; public EreignisArgument(String s) this.meldung = s; 27
Ein C# Beispiel: Das Hauptprogramm Dies Event Methoden der Klasse Abonnent können als Ereignis-Behandlungs-Methode angemeldet werden. class Program static void Main() Herausgeber herausgeber = new Herausgeber(); Abonnent abo = new Abonnent(); //Registriere Abonnent-Methoden als Ereignis-Behandler herausgeber.registriere(abo.eventmethode1); herausgeber.registriere(abo.eventmethode2); //Der Herausgeber erzeugt ein Ereignis herausgeber.publiziere("ereignis 17"); Console.ReadLine(); 28
Beispiel Timer 29
Die Klasse Zeitgeber Der Herausgeber public class Zeitgeber public delegate void EreignisDelegat(TickArgument e); private event EreignisDelegat ereignisbehandler; // Uhr starten public void Start() while (true) TickArgument te = new TickArgument(DateTime.Now); ereignisbehandler(te); System.Threading.Thread.Sleep(1000); // eine Sekunde warten public void Registriere(ZeitEmpfaenger m) ereignisbehandler += m.ausgabe; 30
Die Klasse ZeitEmpfaenger Der Abonnent // Der Abonnent public class ZeitEmpfaenger public void Ausgabe(TickArgument e) System.Console.Clear(); System.Console.WriteLine("\n 0:G", e.time); //Die Ereignis Argumente public class TickArgument : EventArgs public DateTime Time; public TickArgument(DateTime t) this.time = t; 31
Ein C# Beispiel: Das Hauptprogramm Das Hauptprogrammerzeugtden Herausgeber(Zeitgeber) und den Abonnenten(ZeitEmpfaenger), dann registriert sich der Zeitgeber beim ZeitEmpfaenger, zuletzt wird der Zeitgeber(die Uhr) gestartet. class Program static void Main() Zeitgeber m = new Zeitgeber(); ZeitEmpfaenger l = new ZeitEmpfaenger(); m.registriere(l); m.start(); 32
Beispiel Überwachte Eigenschaft Ereignis-Argumente 33
Die Klasse Informationstraeger Der Herausgeber Die Klasse Informationstraeger verbreitet an alle (angemeldeten) Abonnenten ihre Information(en), sobald diese sich ändern. public class Informationstraeger public delegate void EreignisDelegat(EreignisArgumente e); private event EreignisDelegat ereignisbehandler; private string information; // überwachte Information public void Registrierung(Abonnent abo) ereignisbehandler += abo.infoempfang; Die setinformation Methode dient zum Ändern der Information und benachrichtigt über die Änderung public void setinformation(string n) this.information = n; EreignisArgumente ea = new EreignisArgumente(information); ereignisbehandler(ea); 34
Die Klasse MeinAbonnent Informations-Empfänger Die Methode InfoEmpfang der Klasse MeinAbonnentwird jedes Mal aufgerufen, sobald sich die Information beim Informationsträger ändert. public class Abonnent public void InfoEmpfang(EreignisArgumente e) Console.WriteLine("\nNeue Info: 0", e.meldung); 35
Die Klasse MeinAbonnent Informations-Empfänger Die Klasse EreignisArgumentedient zum Übertragen der neuen Informationen (Meldungen) an die angemeldeten Abonnenten. public class EreignisArgumente : EventArgs public string meldung; public EreignisArgumente(String s) this.meldung = s; 36
Das Hauptprogramm Die Main Methode erzeugt zuerst den Informationsträger und dann einen Abonnenten. Der Abonnent wird dann beim Informationsträger registriert. Die Methode setinfoändert die Information beim Informationsträger, was die Benachrichtigung des Abonnenten auslöst. class Program static void Main(string[] args) Informationstraeger infotraeger = new Informationstraeger(); Abonnent abonnent = new Abonnent(); infotraeger.registrierung(abonnent); infotraeger.setinformation("spielstand 2:0"); infotraeger.setinformation("spielstand 3:1"); infotraeger.setinformation("spielstand 4:2"); Console.ReadLine(); 37