Delegates und Events
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 43 von 70.
Ein Delegat ist ein Typ, der eine Referenz auf eine Methode darstellt. Stell dir ihn als eine Variable vor, die statt Daten eine Methode enthält. Dadurch kannst du Methoden als Argumente übergeben, sie in Sammlungen speichern und sie dynamisch aufrufen.
Du deklarierst einen Delegaten, indem du die Methodensignatur angibst, auf die er verweisen kann:
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// Verwendung
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alert: System startedEreignisse bauen auf Delegaten auf, um das Publish-Subscribe-Muster zu implementieren. Eine Klasse löst ein Ereignis aus, und andere Klassen können es abonnieren, um Benachrichtigungen zu erhalten. Das Schlüsselwort event schränkt ein, wie der Delegate verwendet werden kann – Abonnenten können Handler nur hinzufügen oder entfernen, das Ereignis jedoch nicht direkt auslösen.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Benachrichtige alle Abonnenten
}
}
// Abonnieren
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Button wurde geklickt!Der Operator += abonniert einen Handler, während -= das Abonnement aufhebt. Das Muster ?.Invoke() ruft das Ereignis sicher nur auf, wenn es Abonnenten gibt. Ereignisse sind grundlegend für GUI-Anwendungen, Spiele-Engines und jedes System, in dem Objekte auf Änderungen reagieren müssen, ohne eng gekoppelt zu sein.
Aufgabe
EinfachErstellen wir ein Temperaturüberwachungssystem, das Delegates und Ereignisse verwendet, um Abonnenten jedes Mal zu benachrichtigen, wenn sich die Temperatur ändert. Dies ist ein klassisches Beispiel für das Publish-Subscribe-Muster, das durch Ereignisse so elegant ermöglicht wird.
Du wirst deinen Code auf zwei Dateien verteilen:
TemperatureMonitor.cs: Erstelle eineTemperatureMonitor-Klasse im NamespaceMonitoring, die als Publisher fungiert. Deine Überwachung sollte:- ein privates Feld zum Speichern der aktuellen Temperatur besitzen
- ein Ereignis mit
Action<int>namensTemperatureChangeddeklarieren, das jedes Mal ausgelöst wird, wenn die Temperatur aktualisiert wird - eine
Temperature-Eigenschaft (int) besitzen, deren Setter das private Feld aktualisiert und das Ereignis mit dem neuen Temperaturwert auslöst
?.Invoke()-Muster zu verwenden, um das Ereignis nur dann sicher auszulösen, wenn Abonnenten vorhanden sind.Program.cs: Erstelle in deiner Hauptdatei eineTemperatureMonitor-Instanz und abonniere zwei verschiedene Handler für ihrTemperatureChanged-Ereignis:- Einen Handler, der Folgendes ausgibt:
Alert: Temperature is now {value} degrees - Einen weiteren Handler, der Folgendes ausgibt:
Logged: {value}
- Einen Handler, der Folgendes ausgibt:
Du erhältst zwei Eingaben:
- Erster Temperaturwert (Ganzzahl)
- Zweiter Temperaturwert (Ganzzahl)
Wenn die Eingaben beispielsweise 25 und 30 lauten, sollte die Ausgabe wie folgt aussehen:
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Beachte, wie das Setzen der Temperature-Eigenschaft automatisch alle Abonnenten benachrichtigt – die Überwachung muss nichts darüber wissen, wer zuhört. Das ist die Stärke des ereignisgesteuerten Ansatzes!
Probier es selbst
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Eingabe lesen
int temp1 = Convert.ToInt32(Console.ReadLine());
int temp2 = Convert.ToInt32(Console.ReadLine());
// TODO: Erstelle eine TemperatureMonitor-Instanz
// TODO: Subscribe a handler that prints: "Alert: Temperature is now {value} degrees"
// TODO: Abonniere einen weiteren Handler, der ausgibt: "Logged: {value}"
// TODO: Setze die Temperatur auf temp1
// TODO: Setze die Temperatur auf temp2
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition statt VererbungGenerics (Klassen & Methoden)Delegates und EventsAttribute und ReflectionIDisposable & using-AnweisungGrundlagen der Dependency Injection3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler