Delegates und Events
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 43 von 70.
Ein Delegate ist ein Typ, der einen Verweis auf eine Methode darstellt. Stellen Sie es sich wie eine Variable vor, die eine Methode anstelle von Daten enthält. Dies ermöglicht es Ihnen, Methoden als Argumente zu übergeben, sie in Sammlungen zu speichern und sie dynamisch aufzurufen.
Sie deklarieren einen Delegaten, indem Sie die Methodensignatur angeben, 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 startedEvents bauen auf Delegaten auf, um das Publish-Subscribe-Muster zu implementieren. Eine Klasse löst ein Ereignis aus, und andere Klassen können dieses abonnieren, um Benachrichtigungen zu erhalten. Das Schlüsselwort event schränkt die Verwendung des Delegaten ein – Abonnenten können nur Handler hinzufügen oder entfernen, aber das Ereignis nicht direkt aufrufen.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Alle Abonnenten benachrichtigen
}
}
// Abonnieren
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Button wurde geklickt!Der +=-Operator abonniert einen Handler, während -= diesen wieder abmeldet. Das ?.Invoke()-Muster ruft das Event nur dann sicher auf, wenn Abonnenten vorhanden sind. Events sind grundlegend für GUI-Anwendungen, Game-Engines und jedes System, in dem Objekte ohne enge Kopplung auf Änderungen reagieren müssen.
Aufgabe
EinfachLassen Sie uns ein Temperaturüberwachungssystem bauen, das Delegaten und Ereignisse verwendet, um Abonnenten zu benachrichtigen, wann immer sich die Temperatur ändert. Dies ist ein klassisches Beispiel für das Publish-Subscribe-Muster, das Ereignisse so elegant ermöglichen.
Sie werden Ihren Code über zwei Dateien organisieren:
TemperatureMonitor.cs: Erstellen Sie eineTemperatureMonitor-Klasse im NamespaceMonitoring, die als Publisher fungiert. Ihr Monitor sollte:- Ein privates Feld haben, um die aktuelle Temperatur zu speichern
- Ein Ereignis unter Verwendung von
Action<int>namensTemperatureChangeddeklarieren, das ausgelöst wird, wann immer die Temperatur aktualisiert wird - Eine
Temperature-Eigenschaft (int) haben, bei der der Setter das private Feld aktualisiert und das Ereignis mit dem neuen Temperaturwert auslöst
?.Invoke()-Muster zu verwenden, um das Ereignis sicher nur dann auszulösen, wenn Abonnenten vorhanden sind.Program.cs: Erstellen Sie in Ihrer Hauptdatei einenTemperatureMonitorund abonnieren Sie zwei verschiedene Handler für seinTemperatureChanged-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:
Sie erhalten zwei Eingaben:
- Erster Temperaturwert (Ganzzahl)
- Zweiter Temperaturwert (Ganzzahl)
Wenn die Eingaben beispielsweise 25 und 30 sind, sollte die Ausgabe wie folgt aussehen:
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Beachten Sie, wie das Setzen der Temperature-Eigenschaft automatisch alle Abonnenten benachrichtigt - der Monitor muss nichts darüber wissen, wer zuhört. Das ist das Schöne am ereignisgesteuerten Ansatz!
Spickzettel
Ein Delegate ist ein Typ, der einen Verweis auf eine Methode darstellt und es Ihnen ermöglicht, Methoden als Argumente zu übergeben, sie in Sammlungen zu speichern und sie dynamisch aufzurufen.
Deklarieren Sie ein Delegate, indem Sie die Methodensignatur angeben:
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// Usage
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alert: System startedEvents implementieren das Publish-Subscribe-Muster mithilfe von Delegates. Das Schlüsselwort event schränkt die Verwendung von Delegates ein – Abonnenten können nur Handler hinzufügen oder entfernen, das Event jedoch nicht direkt auslösen.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Notify all subscribers
}
}
// Subscribing
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Button was clicked!Verwenden Sie +=, um einen Handler zu abonnieren, und -=, um das Abonnement zu kündigen. Das Muster ?.Invoke() ruft das Event sicher nur dann auf, wenn Abonnenten vorhanden sind.
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: Abonniere einen Handler, der Folgendes ausgibt: "Alert: Temperature is now {value} degrees"
// TODO: Abonniere einen weiteren Handler, der Folgendes 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. EigenschaftenKonstruktorenObjekt-InitialisiererZusammenfassung - Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (:) SyntaxDas 'base'-SchlüsselwortVirtual & Override SchlüsselwörterVersiegelte KlassenDie 'object'-BasisklasseZusammenfassung – Mitarbeiter-Hierarchie7Fortgeschrittene Funktionen
OperatorüberladungIndexer (this[])ToString() überschreibenErweiterungsmethodenZusammenfassung - Benutzerdefinierte Liste2Eigenschaften & Statische Member
Automatisch implementierte EigenschaftenRead-Only- & Write-Only-EigenschaftenStatische Felder & MethodenStatische KlassenExpression-Bodied Member5Polymorphismus & Interfaces
Compile- vs. Runtime-PolymorphismusInterface vs. abstrakte KlasseMehrfache InterfacesExplizite InterfacesUpcasting & DowncastingRecap – Shape Calculator8Fortgeschrittene OOP-Konzepte
Komposition statt VererbungGenerics (Klassen & Methoden)Delegates und EventsAttribute und ReflectionIDisposable & using-AnweisungDependency Injection Grundlagen3Klassenarchitektur
Instanz- vs. statische Daten'readonly' & 'const' SchlüsselwörterBacking FieldsZusammenfassung - Bankkonto-Manager6Kapselung
ZugriffsmodifikatorenProperties zur KapselungImplementierung von Data HidingImmutability-MusterRückblick – Studierendendaten