Delegate (CLI)
Ein Delegat ist eine Form des Typsicherheitsfunktionszeigers, der von der Common Language Infrastructure (CLI) verwendet wird. Delegates legen eine Methode zum Aufrufen und optional ein Objekt für den Methodenaufruf fest. Delegates werden unter anderem eingesetzt, um Callbacks und Event-Listener zu implementieren. Ein Delegatobjekt kapselt einen Verweis auf eine Methode. Das Delegatobjekt kann dann an ein Stück Code übergeben werden, der die referenzierte Methode aufrufen kann, ohne zur Kompilierzeit wissen zu müssen, welche Methode aufgerufen wird.
Ein Multicast-Delegat ist ein Delegat, das auf mehrere Methoden verweist.[1][2] Die Multicast-Delegierung ist ein Mechanismus, der Funktionalität bereitstellt, um mehr als eine Methode auszuführen. Es gibt eine Liste von Delegates, die intern gepflegt werden. Wird nun der Multicast-Delegat aufgerufen, wird diese Liste der Delegates ausgeführt.
In C# werden häufig Delegates verwendet, um Rückrufe in der ereignisgesteuerten Programmierung zu implementieren. Beispielsweise kann ein Delegat verwendet werden, um anzugeben, welche Methode aufgerufen werden soll, wenn der Benutzer auf eine Schaltfläche klickt. Delegates erlauben dem Programmierer, mehrere Methoden vom Eintreten eine Ereignisses zu benachrichtigen.[3]
C#-Codebeispiel
[Bearbeiten | Quelltext bearbeiten]Der Code unten deklariert ein delegate
-Typ, heißt SendMessageDelegate
, nimmt als Parameter eine Message
und gibt ein void
zurück:
delegate void SendMessageDelegate(Message message);
Code, um eine Methode zu definieren, die ein instantiiertes Delegat als Argument annimmt:
void SendMessage(SendMessageDelegate sendMessageDelegateReference)
{
// Rufe das Delegate und jedes andere verbundene Delegate synchron auf
sendMessageDelegateReference(new Message("hello this is a sample message"));
}
Die implementierte Methode, die ausgeführt wird, wenn das Delegat aufgerufen wird:
void HandleSendMessage(Message message)
{
// Die Implementation für die Sender- und die Message-Klasse sind in diesem Beispiel irrelevant
Sender.Send(message);
}
Code, um die SendMessageDelegate
-Methode aufzurufen, wobei ein instantiiertes Delegat als Argument übergeben wird:
SendMessage(new SendMessageDelegate(HandleSendMessage));
Delegates (C#)
[Bearbeiten | Quelltext bearbeiten]delegate void Notifier(string sender); // Normale Signatur mit dem Schlüsselwort delegate
Notifier greetMe; // Delegate-Variable
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
greetMe = new Notifier(HowAreYou);
Eine Delegatvariable ruft die zugehörige Methode auf und wird selber wie folgt aufgerufen:
greetMe("Anton"); // Ruft HowAreYou("Anton") auf und druckt "How are you, Anton?" aus
Delegatvariablen sind First-Class-Objekts der Form new DelegateType(obj.Method)
und können jeder passenden Methode oder dem Wert null
zugeordnet werden. Sie speichern eine Methode und ihren Empfänger ohne Parameter:[4]
new DelegateType(funnyObj.HowAreYou);
Das Objekt funnyObj
kann this
sein und weggelassen werden. Wenn die Methode static
ist, sollte sie nicht das Objekt sein (auch als Instanz in anderen Sprachen bezeichnet), sondern die Klasse selbst. Es sollte nicht abstract
sein, sondern könnte new
, override
oder virtuel
.
Um eine Methode erfolgreich mit einem Delegat aufzurufen, muss die Methodensignatur dem DelegateType
mit derselben Anzahl gleichartiger Parameter (ref
, out
, value
) und demselben Typ (einschließlich Rückgabetyp) entsprechen.
Multicast-Delegates (C#)
[Bearbeiten | Quelltext bearbeiten]Eine Delegat-Variable kann mehrere Werte gleichzeitig enthalten:
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
void HowAreYouToday(string sender) {
Console.WriteLine("How are you today, " + sender + '?');
}
Notifier greetMe;
greetMe = HowAreYou;
greetMe += HowAreYouToday;
greetMe("Leonardo"); // "How are you, Leonardo?"
// "How are you today, Leonardo?"
greetMe -= HowAreYou;
greetMe("Pereira"); // "How are you today, Pereira?"
Wenn der Multicast-Delegat eine Funktion ist oder kein Parameter out
hat, wird der Parameter des letzten Aufrufs zurückgegeben.[5]
Technische Details
[Bearbeiten | Quelltext bearbeiten]Obwohl interne Implementierungen variieren können, können Delegate-Instanzen als Tupel eines Objekts und eines Methodenzeigers und eines Verweises (möglicherweise null
) auf einen anderen Delegaten gedacht werden. Daher ist ein Verweis auf einen Delegierten möglicherweise ein Hinweis auf mehrere Delegierte. Wenn der erste Delegat beendet ist, wenn seine Kettenreferenz nicht null ist, wird der nächste aufgerufen, und so weiter, bis die Liste vollständig ist. Dieses Muster ermöglicht es einem Ereignis, Overhead-Skalierung leicht von dem eines einzelnen Verweises bis zum Versand zu einer Liste von Delegaten zu haben, und ist weit verbreitet in der CLI verwendet.
Leistung
[Bearbeiten | Quelltext bearbeiten]Die Leistung von Delegates war viel langsamer als eine virtuelle oder Interface-Methode aufzurufen (ein 1/6 bis 1/8 Mal so schnell in Microsoft 2003 Benchmarks),[6] aber seit dem .NET 2.0 CLR im Jahr 2005 ist es ungefähr gleich schnell wie Interface-Aufrufe.[7] D.h., dass es einen kleinen zusätzlichen Overhead im Vergleich zu direkten Methodenaufrufen gibt.
Es gibt sehr strenge Regeln für den Bau von delegierten Klassen.
Siehe auch
[Bearbeiten | Quelltext bearbeiten]Weblinks
[Bearbeiten | Quelltext bearbeiten]- Delegate Class .NET Framework (current version)
- What is .Net Delegates
- Sun’s White Paper on Delegates ( vom 27. Juni 2012 im Internet Archive)
- Microsoft answer to Sun ( vom 23. September 2009 im Internet Archive)
- The dark side of C# Delegates
Einzelnachweise
[Bearbeiten | Quelltext bearbeiten]- ↑ How to: Combine Delegates (Multicast Delegates)(C# Programming Guide). msdn.microsoft.com, abgerufen am 20. Mai 2008.
- ↑ About Microsoft’s “Delegates”. In: Sun Developer Network. Sun Microsystems, archiviert vom am 10. Februar 1999 .
- ↑ Wikibooks: C Sharp Programming/Delegates and Events.
- ↑ Hanspeter Mössenböck: Advanced C#: Variable Number of Parameters. Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik, 25. März 2002, S. 23–24, abgerufen am 4. August 2011.
- ↑ Hanspeter Mössenböck: Advanced C#: Variable Number of Parameters. Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik, 25. März 2002, abgerufen am 4. August 2011.
- ↑ Jan Gray: Writing Faster Managed Code: Know What Things Cost. Microsoft, Juni 2003, abgerufen am 9. September 2007.
- ↑ Oliver Sturm: Delegate calls vastly sped up in .NET 2. 1. September 2005, abgerufen am 9. September 2007.