System.Delegate und das delegate-SchlüsselwortSystem.Delegate and the delegate keyword

ZurückPrevious

Dieser Artikel behandelt die Klassen in .NET Framework, die Delegaten unterstützen, und wie diese zum delegate-Schlüsselwort zugeordnet werden.This article will cover the classes in the .NET framework that support delegates, and how those map to the delegate keyword.

Definieren von DelegattypenDefining Delegate Types

Wir beginnen mit dem Schlüsselwort „delegate“, da Sie dieses beim Arbeiten mit Delegaten hauptsächlich verwenden werden.Let's start with the 'delegate' keyword, because that's primarily what you will use as you work with delegates. Der Code, der vom Compiler bei Verwendung des delegate-Schlüsselworts generiert wird, verweist auf Methodenaufrufe, die Member der Klassen Delegate und MulticastDelegate aufrufen.The code that the compiler generates when you use the delegate keyword will map to method calls that invoke members of the Delegate and MulticastDelegate classes.

Sie definieren einen Delegattyp, der Syntax verwendet, die dem Definieren einer Methodensignatur ähnlich ist.You define a delegate type using syntax that is similar to defining a method signature. Sie fügen das delegate-Schlüsselwort einfach der Definition hinzu.You just add the delegate keyword to the definition.

Wir verwenden die List.Sort()-Methode weiterhin als Beispiel.Let's continue to use the List.Sort() method as our example. Der erste Schritt ist die Erstellung eines Typs für den Vergleichsdelegaten:The first step is to create a type for the comparison delegate:

// From the .NET Core library

// Define the delegate type:
public delegate int Comparison<in T>(T left, T right);

Der Compiler generiert eine von System.Delegate abgeleitete Klasse, die der verwendeten Signatur entspricht (in diesem Fall eine Methode, die eine ganze Zahl zurückgibt und über zwei Argumente verfügt).The compiler generates a class, derived from System.Delegate that matches the signature used (in this case, a method that returns an integer, and has two arguments). Der Typ des Delegaten ist Comparison.The type of that delegate is Comparison. Der Delegattyp Comparison ist ein generischer Typ.The Comparison delegate type is a generic type. Weitere Informationen zu Generika finden Sie hier.For details on generics see here.

Beachten Sie, dass es so scheinen kann, als ob die Syntax eine Variable deklariert, aber tatsächlich deklariert sie einen Typ.Notice that the syntax may appear as though it is declaring a variable, but it is actually declaring a type. Sie können Delegattypen innerhalb von Klassen, direkt in Namespaces oder sogar im globalen Namespace definieren.You can define delegate types inside classes, directly inside namespaces, or even in the global namespace.

Hinweis

Es wird nicht empfohlen, Delegattypen (oder andere Typen) direkt im globalen Namespace zu deklarieren.Declaring delegate types (or other types) directly in the global namespace is not recommended.

Der Compiler generiert auch Handler zum Hinzufügen und Entfernen für diesen neuen Typ, damit Clients dieser Klasse Methoden der Aufrufliste einer Instanz hinzufügen und entfernen können.The compiler also generates add and remove handlers for this new type so that clients of this class can add and remove methods from an instance's invocation list. Der Compiler erzwingt, dass die Signatur der Methode, die hinzugefügt oder entfernt wird, der Signatur bei der Deklaration der Methode entspricht.The compiler will enforce that the signature of the method being added or removed matches the signature used when declaring the method.

Deklarieren von Instanzen von DelegatenDeclaring instances of delegates

Nach dem Definieren des Delegats können Sie eine Instanz dieses Typs erstellen.After defining the delegate, you can create an instance of that type. Wie alle Variablen in C# können Sie Delegatinstanzen nicht direkt in einem Namespace oder im globalen Namespace deklarieren.Like all variables in C#, you cannot declare delegate instances directly in a namespace, or in the global namespace.

// inside a class definition:

// Declare an instance of that type:
public Comparison<T> comparator;

Der Typ der Variable ist Comparison<T>, der zuvor definierte Delegattyp.The type of the variable is Comparison<T>, the delegate type defined earlier. Der Name der Variablen ist comparator.The name of the variable is comparator.

Dieser obenstehende Codeausschnitt hat eine Membervariable innerhalb einer Klasse deklariert.That code snippet above declared a member variable inside a class. Sie können auch Delegatvariablen deklarieren, die lokale Variablen oder Argumente von Methoden sind.You can also declare delegate variables that are local variables, or arguments to methods.

Aufrufen von DelegatenInvoking Delegates

Sie rufen die Methoden in der Aufrufliste eines Delegaten auf, indem Sie diesen Delegaten aufrufen.You invoke the methods that are in the invocation list of a delegate by calling that delegate. In der Sort()-Methode ruft der Code die Vergleichsmethode an, um zu bestimmen, in welcher Reihenfolge er die Objekte anordnet:Inside the Sort() method, the code will call the comparison method to determine which order to place objects:

int result = comparator(left, right);

In der Zeile darüber ruft der Code die Methode auf, die an den Delegaten angefügt ist.In the line above, the code invokes the method attached to the delegate. Sie behandeln die Variable als Methodenname und rufen sie mit der üblichen Syntax für Methodenaufrufe auf.You treat the variable as a method name, and invoke it using normal method call syntax.

Diese Codezeile macht eine unsichere Annahme: Es gibt keine Garantie, dass dem Delegaten ein Ziel hinzugefügt wurde.That line of code makes an unsafe assumption: There's no guarantee that a target has been added to the delegate. Wenn keine Ziele angehängt wurden, löst die Zeile darüber eine NullReferenceException aus.If no targets have been attached, the line above would cause a NullReferenceException to be thrown. Die Ausdrücke, die verwendet werden, um dieses Problem zu beheben, sind komplizierter als eine einfache NULL-Überprüfung und werden später in dieser Reihe behandelt.The idioms used to address this problem are more complicated than a simple null-check, and are covered later in this series.

Zuweisen, Hinzufügen und Entfernen von AufrufzielenAssigning, Adding and removing Invocation Targets

So werden Delegattypen definiert und Delegatinstanzen deklariert und aufgerufen.That's how a delegate type is defined, and how delegate instances are declared and invoked.

Entwickler, die die List.Sort()-Methode verwenden möchten, müssen eine Methode definieren, deren Signatur der Definition des Delegattypen entspricht, und diese dem Delegaten zuweisen, der von der sort-Methode verwendet wird.Developers that want to use the List.Sort() method need to define a method whose signature matches the delegate type definition, and assign it to the delegate used by the sort method. Diese Zuordnung fügt die Methode der Aufrufliste des Delegatobjekts hinzu.This assignment adds the method to the invocation list of that delegate object.

Nehmen wir an, Sie möchten eine Liste von Zeichenfolgen nach Länge sortieren.Suppose you wanted to sort a list of strings by their length. Die Vergleichsfunktion kann folgende sein:Your comparison function might be the following:

private static int CompareLength(string left, string right)
{
    return left.Length.CompareTo(right.Length);
}

Die Methode wird als private Methode deklariert.The method is declared as a private method. Das ist in Ordnung.That's fine. Möglicherweise möchten Sie nicht, dass diese Methode Teil der öffentlichen Schnittstelle ist.You may not want this method to be part of your public interface. Sie kann dennoch als Vergleichsmethode verwendet werden, wenn sie an einen Delegaten angefügt wird.It can still be used as the comparison method when attached to a delegate. Der aufrufende Code wird diese Methode an die Zielliste des Delegatobjekts anfügen lassen und kann über diesen Delegaten darauf zugreifen.The calling code will have this method attached to the target list of the delegate object, and can access it through that delegate.

Sie erstellen diese Beziehung durch Übergeben dieser Methode an die List.Sort()-Methode:You create that relationship by passing that method to the List.Sort() method:

phrases.Sort(CompareLength);

Beachten Sie, dass der Name der Methode ohne Klammern verwendet wird.Notice that the method name is used, without parentheses. Das Verwenden der Methode als Argument teilt dem Compiler mit, dass er den Methodenverweis in einen Verweis konvertieren soll, der als Delegataufrufziel verwendet werden kann, und diese Methode als Aufrufziel anfügen soll.Using the method as an argument tells the compiler to convert the method reference into a reference that can be used as a delegate invocation target, and attach that method as an invocation target.

Sie könnten auch explizit eine Variable vom Typ „Comparison“ deklarieren und diese in der Zuordnung verwenden:You could also have been explicit by declaring a variable of type 'Comparison` and doing an assignment:

Comparison<string> comparer = CompareLength;
phrases.Sort(comparer);

Wenn es sich bei der als Delegatziel verwendeten Methode um eine kleine Methode handelt, wird gewöhnlich die Lambda-Ausdruck-Syntax für die Durchführung der Zuweisung verwendet:In uses where the method being used as a delegate target is a small method, it's common to use Lambda Expression syntax to perform the assignment:

Comparison<string> comparer = (left, right) => left.Length.CompareTo(right.Length);
phrases.Sort(comparer);

Die Verwendung von Lambda-Ausdrücken für Delegatziele wird in einem späteren Abschnitt ausführlicher behandelt.Using Lambda Expressions for delegate targets is covered more in a later section.

Das Sort()-Beispiel fügt dem Delegaten typischerweise eine einzelne Zielmethode an.The Sort() example typically attaches a single target method to the delegate. Allerdings unterstützen Delegatobjekte Aufruflisten mit mehreren Zielmethoden, die an ein Delegatobjekt angefügt sind.However, delegate objects do support invocation lists that have multiple target methods attached to a delegate object.

Delegatklassen und MulticastDelegate-KlassenDelegate and MulticastDelegate classes

Die oben beschriebene Sprachunterstützung bietet die Funktionen und Unterstützung, die Sie in der Regel bei der Arbeit mit Delegaten benötigen.The language support described above provides the features and support you'll typically need to work with delegates. Diese Funktionen basieren auf zwei Klassen von .NET Core-Framework: Delegate und MulticastDelegate.These features are built on two classes in the .NET Core framework: Delegate and MulticastDelegate.

Die System.Delegate-Klasse und ihre einzige direkte untergeordnete Klasse System.MulticastDelegate bieten die Framework-Unterstützung für das Erstellen von Delegaten, das Registrieren von Methoden als Delegatziele und das Aufrufen aller Methoden, die als Delegatziel registriert sind.The System.Delegate class, and its single direct sub-class, System.MulticastDelegate, provide the framework support for creating delegates, registering methods as delegate targets, and invoking all methods that are registered as a delegate target.

Interessanterweise sind die Klassen System.Delegate und System.MulticastDelegate selbst keine Delegattypen.Interestingly, the System.Delegate and System.MulticastDelegate classes are not themselves delegate types. Sie bieten die Grundlage für alle spezifischen Delegattypen.They do provide the basis for all specific delegate types. Derselbe Sprachentwurfsprozess verlangte, dass keine Klasse deklariert werden kann, die von Delegate oder MulticastDelegate abgeleitet wird.That same language design process mandated that you cannot declare a class that derives from Delegate or MulticastDelegate. Die C#-Sprachregeln verbieten dies.The C# language rules prohibit it.

Stattdessen erstellt der C#-Compiler Instanzen einer von MulticastDelegate abgeleiteten Klasse, wenn Sie das C#-Schlüsselwort verwenden, um Delegattypen zu deklarieren.Instead, the C# compiler creates instances of a class derived from MulticastDelegate when you use the C# language keyword to declare delegate types.

Dieser Entwurf hat seinen Ursprung in der ersten Version von C# und .NET.This design has its roots in the first release of C# and .NET. Ein Ziel des Entwurfsteams war sicherzustellen, dass die Sprache bei der Verwendung von Delegaten Typsicherheit erzwingt.One goal for the design team was to ensure that the language enforced type safety when using delegates. Dies bedeutete sicherzustellen, dass Delegaten mit dem richtigen Typ und der richtigen Anzahl von Argumenten aufgerufen werden.That meant ensuring that delegates were invoked with the right type and number of arguments. Zudem sollte jeder Rückgabetyp zur Kompilierzeit richtig angegeben werden.And, that any return type was correctly indicated at compile time. Delegaten waren Teil von .NET Version 1.0, die es vor Generika gab.Delegates were part of the 1.0 .NET release, which was before generics.

Die beste Möglichkeit, diese Typsicherheit zu erzwingen, bestand darin, dass der Compiler die konkreten Delegatklassen erstellt, die die verwendete Methodensignatur darstellten.The best way to enforce this type safety was for the compiler to create the concrete delegate classes that represented the method signature being used.

Obwohl Sie abgeleitete Klassen nicht direkt erstellen können, verwenden Sie die Methoden, die auf diesen Klassen definiert sind.Even though you cannot create derived classes directly, you will use the methods defined on these classes. Nun sehen wir uns die am häufigsten verwendeten Methoden an, die Sie beim Arbeiten mit Delegaten verwenden werden.Let's go through the most common methods that you will use when you work with delegates.

An erster Stelle müssen Sie beachten, dass jeder Delegat, mit dem Sie arbeiten, von MulticastDelegate abgeleitet ist.The first, most important fact to remember is that every delegate you work with is derived from MulticastDelegate. Ein Multicastdelegat bedeutet, dass mehr als ein Methodenziel beim Aufrufen über einen Delegaten aufgerufen werden kann.A multicast delegate means that more than one method target can be invoked when invoking through a delegate. Der ursprüngliche Entwurf sah eine Unterscheidung vor zwischen Delegaten, bei denen nur eine Zielmethode angefügt und aufgerufen werden konnte, und Delegaten, bei denen mehrere Zielmethoden angefügt und aufgerufen werden konnten.The original design considered making a distinction between delegates where only one target method could be attached and invoked, and delegates where multiple target methods could be attached and invoked. Diese Unterscheidung erwies sich in der Praxis jedoch als weniger nützlich als ursprünglich gedacht.That distinction proved to be less useful in practice than originally thought. Die zwei verschiedenen Klassen wurden bereits erstellt und befinden sich seit der ersten Veröffentlichung im Framework.The two different classes were already created, and have been in the framework since its initial public release.

Die Methoden, die Sie bei der Arbeit mit Delegaten am häufigsten verwenden, sind Invoke() und BeginInvoke() / EndInvoke().The methods that you will use the most with delegates are Invoke() and BeginInvoke() / EndInvoke(). Invoke() ruft alle Methoden auf, die an eine bestimmte Delegatinstanz angefügt wurden.Invoke() will invoke all the methods that have been attached to a particular delegate instance. Wie oben gezeigt, werden Delegaten in der Regel mit der Aufrufsyntax-Methode auf der Delegatvariablen aufgerufen.As you saw above, you typically invoke delegates using the method call syntax on the delegate variable. Wie Sie später in dieser Reihe sehen werden, gibt es Muster, die direkt mit diesen Methoden arbeiten.As you'll see later in this series, there are patterns that work directly with these methods.

Nun haben Sie die Sprachsyntax und die Klassen gesehen, die Delegaten unterstützen. Als Nächstes untersuchen wir, wie stark typisierte Delegaten verwendet, erstellt und aufgerufen werden.Now that you've seen the language syntax and the classes that support delegates, let's examine how strongly typed delegates are used, created and invoked.

WeiterNext