Die Übersetzung des Artikels wurde speziell für Studenten des Kurses "C # Developer" erstellt .

Was sind Ereignisse in C #?
Ein Ereignis kann verwendet werden, um Benachrichtigungen bereitzustellen. Sie können die Veranstaltung abonnieren, wenn Sie diese Benachrichtigungen benötigen. Sie können auch eigene Ereignisse erstellen, die Sie darüber informieren, dass etwas passiert ist, das Sie interessiert. Das .NET Framework bietet integrierte Typen, mit denen Sie Ereignisse erstellen können. Mit Delegaten, Lambda-Ausdrücken und anonymen Methoden können Sie Ereignisse auf bequeme Weise erstellen und verwenden.
Grundlegendes zu Delegaten in C #
In C # bilden Delegaten die Grundbausteine für Ereignisse. Ein Delegat ist ein Typ, der die Signatur einer Methode definiert. In C ++ kann dies beispielsweise mithilfe eines Funktionszeigers erfolgen. In C # können Sie eine Instanz eines Delegaten erstellen, die auf eine andere Methode verweist. Sie können diese Methode über die Delegateninstanz aufrufen.
Das Folgende ist ein Beispiel für das Deklarieren eines Delegaten und das Aufrufen einer Methode über diesen.
Verwenden eines Delegaten in C #
}class Program { public delegate double MathDelegate(double value1, double value2); public static double Add(double value1, double value2) { return value1 + value2; } public static double Subtract(double value1, double value2) { return value1 - value2; } Console.ReadLine(); public static void Main() { MathDelegate mathDelegate = Add; var result = mathDelegate(5, 2); Console.WriteLine(result);
Wie Sie sehen können, verwenden wir das Schlüsselwort delegate, um dem Compiler mitzuteilen, dass wir einen Delegatentyp erstellen.
Es ist einfach, Delegierte zusammen mit der automatischen Erstellung eines neuen Delegatentyps zu instanziieren.
Sie können auch das
neue Schlüsselwort verwenden, um einen Delegaten zu erstellen.
MathDelegate mathDelegate = new MathDelegate(Add)
;
Ein instanziierter Delegat ist ein Objekt. Sie können es auch verwenden und als Argument an andere Methoden übergeben.
Multicast-Delegierte in C #
Ein weiteres großartiges Merkmal von Delegierten ist, dass Sie sie miteinander kombinieren können. Dies wird als Multicasting bezeichnet. Mit dem Operator + oder + = können Sie der Aufrufliste einer vorhandenen Delegateninstanz eine weitere Methode hinzufügen. In ähnlicher Weise können Sie eine Methode auch mit dem Dekrementierungszuweisungsoperator (- oder - =) aus der Aufrufliste entfernen. Diese Funktion dient als Grundlage für Ereignisse in C #. Das folgende Beispiel zeigt einen Multicast-Delegaten.
class Program { static void Hello(string s) { Console.WriteLine(" Hello, {0}!", s); } static void Goodbye(string s) { Console.WriteLine(" Goodbye, {0}!", s); } delegate void Del(string s); static void Main() { Del a, b, c, d;
Dies ist möglich, weil Delegaten von der
System.MulticastDelegate
Klasse erben, die wiederum von
System.Delegate
erbt. Sie können die in diesen Basisklassen definierten Mitglieder für Ihre Delegaten verwenden.
Um beispielsweise herauszufinden, wie viele Methoden ein Multicast-Delegat aufruft, können Sie den folgenden Code verwenden:
int invocationCount = d.GetInvocationList().GetLength(0);
Kovarianz und Kontravarianz in C #
Wenn Sie einem Delegaten eine Methode zuweisen, muss die Methodensignatur nicht genau mit dem Delegaten übereinstimmen. Dies nennt man Kovarianz und Kontravarianz. Durch Kovarianz kann eine Methode einen abgeleiteten Rückgabetyp haben als den im Delegaten definierten. Die Kontravarianz ermöglicht eine Methode mit Parametertypen, die weniger abgeleitet sind als die Typen im Delegaten.
Kovarianz delegieren
Hier ist ein Beispiel für Kovarianz:
class Program { public delegate TextWriter CovarianceDel(); public static StreamWriter MethodStream() { return null; } public static StringWriter MethodString() { return null; } static void Main() { CovarianceDel del; del = MethodStream; del = MethodString; Console.ReadLine(); } }
Da sowohl
StreamWriter
als auch
StringWriter
von
StringWriter
erben, können Sie
CovarianceDel
mit beiden Methoden verwenden.
Kontravarianz bei Delegierten
Das Folgende ist ein Beispiel für eine Kontravarianz.
class Program { public static void DoSomething(TextWriter textWriter) { } public delegate void ContravarianceDel(StreamWriter streamWriter); static void Main() { ContravarianceDel del = DoSomething; Console.ReadLine(); } }
Da die
DoSomething
Methode mit
TextWriter
, kann sie sicherlich mit
StreamWriter
. Aufgrund von Kontravarianzen können Sie einen Delegaten aufrufen und eine Instanz von
StreamWriter
an die
DoSomething
Methode übergeben.
Mehr über dieses Konzept erfahren Sie
hier .
Lambda-Ausdrücke in C #
Manchmal erfordert eine gesamte Methodensignatur mehr Code als der Hauptteil der Methode. Es gibt auch Situationen, in denen Sie eine gesamte Methode erstellen müssen, um sie als Delegat zu verwenden.
In diesen Fällen hat Microsoft in C # einige neue Funktionen hinzugefügt, z. B. anonyme Methoden in 2.0. In C # 3.0 wurde es noch besser, als Lambda-Ausdrücke hinzugefügt wurden. Der Lambda-Ausdruck ist die bevorzugte Methode beim Schreiben von neuem Code.
Das Folgende ist ein Beispiel für die neueste Lambda-Syntax.
class Program { public delegate double MathDelegate(double value1, double value2); public static void Main() { MathDelegate mathDelegate = (x,y) => x + y; var result = mathDelegate(5, 2); Console.WriteLine(result); // : 7 mathDelegate = (x, y) => x - y; ; result = mathDelegate(5, 2); Console.WriteLine(result); // : 3 Console.ReadLine(); } }
Um diesen Code zu lesen, müssen Sie das Wort "folgt" im Kontext der speziellen Lambda-Syntax verwenden. Zum Beispiel lautet der erste Lambda-Ausdruck im obigen Beispiel "x und y folgen der Addition von x und y".
Eine Lambda-Funktion hat im Gegensatz zu einer Methode keinen bestimmten Namen. Aus diesem Grund werden Lambdas als anonyme Funktionen bezeichnet. Sie müssen den Typ des Rückgabewerts auch nicht explizit angeben. Der Compiler übernimmt dies automatisch von Ihrem Lambda. Im obigen Beispiel werden die Parametertypen x und y ebenfalls nicht explizit angegeben.
Sie können Lambdas erstellen, die mehrere Operatoren umfassen. Sie können dies tun, indem Sie die Aussagen, aus denen das Lambda besteht, in geschweifte Klammern setzen, wie im folgenden Beispiel gezeigt.
MathDelegate mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; };
Manchmal scheint eine Ankündigung eines Delegierten für eine Veranstaltung etwas umständlich zu sein. Aus diesem Grund verfügt .NET Framework über mehrere integrierte Delegatentypen, die Sie beim Deklarieren von Delegaten verwenden können. Im MathDelegate-Beispiel haben Sie den folgenden Delegaten verwendet:
public delegate double MathDelegate(double value1, double value2);
Sie können diesen Delegaten durch einen der integrierten Typen ersetzen, nämlich
Func <int, int, int>
.
so,
class Program { public static void Main() { Func<int, int, int> mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; }; var result = mathDelegate(5, 2); Console.WriteLine(result);
Func <...> -Typen finden Sie im System-Namespace. Sie stellen Delegaten dar, die einen Typ zurückgeben und 0 bis 16 Parameter annehmen. Alle diese Typen werden von System.MulticaseDelegate geerbt, sodass Sie der Aufrufliste mehrere Methoden hinzufügen können.
Wenn Sie einen Delegattyp benötigen, der keinen Wert zurückgibt, können Sie die System.Action-Typen verwenden. Sie können auch 0 bis 16 Parameter annehmen, geben jedoch keinen Wert zurück.
Hier ist ein Beispiel für die Verwendung des Aktionstyps:
class Program { public static void Main() { Action<int, int> mathDelegate = (x,y) => { Console.WriteLine(x + y); }; mathDelegate(5, 2);
Weitere Informationen zu integrierten .NET-Delegaten finden Sie
hier .
Die Dinge werden kompliziert, wenn Ihre Lambda-Funktion beginnt, sich auf Variablen zu beziehen, die außerhalb des Lambda-Ausdrucks deklariert sind, oder auf diese. Wenn ein Steuerelement den Bereich einer Variablen verlässt, wird die Variable normalerweise ungültig. Was aber, wenn der Delegat auf eine lokale Variable verweist? Um dies zu beheben, generiert der Compiler Code, der die Lebensdauer der erfassten Variablen verlängert, mindestens solange der langlebigste Delegat lebt. Dies wird als Schließung bezeichnet.
Hier erfahren Sie mehr über Schließungen.
Ereignisse in C #
Betrachten Sie ein beliebtes Entwicklungsmuster - Publisher-Abonnent (Pub / Sub). Sie können ein Ereignis abonnieren und werden benachrichtigt, wenn der Ereignisverleger ein neues Ereignis initiiert. Dieses System wird verwendet, um eine schwache Kommunikation zwischen Komponenten in einer Anwendung herzustellen.
Der Delegat bildet die Basis für das Ereignissystem in C #.
Eine Veranstaltung ist eine spezielle Art von Delegierten, die eine ereignisorientierte Programmierung ermöglicht. Ereignisse sind Mitglieder einer Klasse, die unabhängig vom Zugriffsspezifizierer nicht außerhalb der Klasse aufgerufen werden können. So würde beispielsweise ein als öffentlich deklariertes Ereignis anderen Klassen erlauben, + = und - = für dieses Ereignis zu verwenden, aber das Auslösen eines Ereignisses (dh das Aufrufen eines Delegaten) ist nur in der Klasse zulässig, die das Ereignis enthält. Schauen wir uns ein Beispiel an:
Anschließend kann eine Methode in einer anderen Klasse das Ereignis abonnieren, indem dem Ereignisdelegaten eine ihrer Methoden hinzugefügt wird:
Das folgende Beispiel zeigt, wie eine Klasse einen offenen Delegaten bereitstellen und ein Ereignis generieren kann.
class Program { static void Main(string[] args) {
Selbst wenn das Ereignis als
public
deklariert ist, kann es nur in der Klasse, in der es sich befindet, direkt ausgelöst werden.
Mit dem Schlüsselwort
event
schützt der Compiler unser Feld vor unerwünschtem Zugriff.
Und auch,
Die Verwendung von = (direkte Delegatenzuweisung) ist nicht zulässig. Daher ist Ihr Code jetzt vor dem Risiko geschützt, frühere Abonnenten durch Verwendung von = anstelle von + = zu löschen.
Darüber hinaus stellen Sie möglicherweise die spezielle OnChange-Feldinitialisierungssyntax für einen leeren Delegaten fest, z. B.
delegate { }
. Dies stellt sicher, dass unser OnChange-Feld niemals null ist. Daher können wir die Nullprüfung vor dem Aufrufen des Ereignisses entfernen, wenn keine anderen Klassenmitglieder es auf Null setzen.
Wenn Sie das obige Programm ausführen, erstellt Ihr Code eine neue Instanz von Pub, abonniert das Ereignis auf zwei verschiedene Arten und generiert ein Ereignis durch Aufrufen von p.Raise. Die Pub-Klasse kennt keinen der Abonnenten. Es wird nur ein Ereignis generiert.
Sie können auch meinen Artikel
C # Publisher-Subscriber Design Pattern lesen
, um ein tieferes Verständnis dieses Konzepts zu erhalten.
Nun, das ist alles für jetzt. Ich hoffe du kommst auf die Idee. Vielen Dank für das Lesen des Beitrags. Bitte lassen Sie mich in den Kommentaren unten wissen, ob Fehler oder Änderungen erforderlich sind. Vielen Dank im Voraus!
Nützliche Links
www.c-sharpcorner.com/blogs/c-sharp-generic-delegates-func-action-and-predicatedocs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariancehttps://web.archive.org/web/20150707082707/http://diditwith.net/PermaLink,guid,235646ae-3476-4893-899d-105e4d48c25b.aspx