Gedelegeerden gebruiken (C#-programmeerhandleiding)
Een gemachtigde is een type dat een methode veilig inkapselt, vergelijkbaar met een functieaanwijzer in C en C++. In tegenstelling tot C-functiepointers zijn gemachtigden objectgeoriënteerd, typen veilig en veilig. Het type gemachtigde wordt gedefinieerd door de naam van de gemachtigde. In het volgende voorbeeld wordt een gemachtigde gede declareerd die Callback
een methode kan inkapselen die een tekenreeks als argument gebruikt en ongeldige waarde retourneert:
public delegate void Callback(string message);
Een gedelegeerde-object wordt normaal gesproken samengesteld door de naam op te geven van de methode die de gedelegeerde inpakt of met een lambda-expressie. Zodra een gemachtigde op deze manier wordt geïnstantieerd, kan deze worden aangeroepen. Als u een gemachtigde aanroept, wordt de methode aangeroepen die is gekoppeld aan het gemachtigde exemplaar. De parameters die door de aanroeper worden doorgegeven aan de gemachtigde, worden doorgegeven aan de methode en de retourwaarde, indien van toepassing, wordt doorgegeven aan de aanroeper door de gemachtigde. Voorbeeld:
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;
// Call the delegate.
handler("Hello World");
Gedelegeerdentypen zijn afgeleid van de Delegate klasse in .NET. Gedelegeerdentypen zijn verzegeld, ze kunnen niet worden afgeleid van en het is niet mogelijk om aangepaste klassen af te leiden van Delegate. Omdat de geïnstantieerde gemachtigde een object is, kan deze worden doorgegeven als argument of worden toegewezen aan een eigenschap. Hiermee kan een methode een gemachtigde als parameter accepteren en de gemachtigde op een later tijdstip aanroepen. Dit wordt een asynchrone callback genoemd en is een veelgebruikte methode om een beller op de hoogte te stellen wanneer een lang proces is voltooid. Wanneer een gemachtigde op deze manier wordt gebruikt, heeft de code die de gemachtigde gebruikt geen kennis nodig van de implementatie van de gebruikte methode. De functionaliteit is vergelijkbaar met de inkapselingsinterfaces.
Een ander veelvoorkomend gebruik van callbacks is het definiëren van een aangepaste vergelijkingsmethode en het doorgeven van die gemachtigde aan een sorteermethode. Hiermee kan de code van de aanroeper deel uitmaken van het sorteeralgoritmen. In de volgende voorbeeldmethode wordt het Del
type als parameter gebruikt:
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
Vervolgens kunt u de hierboven gemaakte gemachtigde doorgeven aan die methode:
MethodWithCallback(1, 2, handler);
en ontvang de volgende uitvoer naar de console:
The number is: 3
Als u de gemachtigde als abstractie gebruikt, MethodWithCallback
hoeft u de console niet rechtstreeks aan te roepen. Het hoeft niet te worden ontworpen met een console in gedachten. Wat MethodWithCallback
doet, is een tekenreeks voorbereiden en de tekenreeks doorgeven aan een andere methode. Dit is vooral krachtig omdat een gedelegeerde methode een willekeurig aantal parameters kan gebruiken.
Wanneer een gemachtigde is samengesteld om een instantiemethode te verpakken, verwijst de gemachtigde naar zowel het exemplaar als de methode. Een gemachtigde heeft geen kennis van het exemplaartype naast de methode die wordt verpakt, zodat een gedelegeerde naar elk type object kan verwijzen zolang er een methode is voor dat object dat overeenkomt met de handtekening van de gemachtigde. Wanneer een gemachtigde is samengesteld om een statische methode te verpakken, verwijst deze alleen naar de methode. Houd rekening met de volgende declaraties:
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}
Naast de statische DelegateMethod
weergave die eerder werd weergegeven, hebben we nu drie methoden die kunnen worden verpakt door een Del
exemplaar.
Een gemachtigde kan meer dan één methode aanroepen wanneer deze wordt aangeroepen. Dit wordt multicasting genoemd. Als u een extra methode wilt toevoegen aan de lijst met methoden van de gedelegeerde( de aanroeplijst), moet u gewoon twee gemachtigden toevoegen met behulp van de operatoren voor optellen of toevoegen van toewijzingen ('+' of '+='). Voorbeeld:
var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;
//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
Op dit punt allMethodsDelegate
staan drie methoden in de aanroeplijst ,Method1
Method2
en DelegateMethod
. De oorspronkelijke drie gemachtigden, d1
, d2
en d3
, blijven ongewijzigd. Wanneer allMethodsDelegate
wordt aangeroepen, worden alle drie de methoden op volgorde aangeroepen. Als de gemachtigde referentieparameters gebruikt, wordt de verwijzing opeenvolgend doorgegeven aan elk van de drie methoden en zijn eventuele wijzigingen per methode zichtbaar voor de volgende methode. Wanneer een van de methoden een uitzondering genereert die niet binnen de methode wordt gevangen, wordt die uitzondering doorgegeven aan de aanroeper van de gemachtigde en worden geen volgende methoden in de aanroeplijst aangeroepen. Als de gemachtigde een retourwaarde en/of out-parameters heeft, retourneert deze de retourwaarde en parameters van de laatste aangeroepen methode. Als u een methode uit de aanroeplijst wilt verwijderen, gebruikt u de toewijzingsoperatoren voor aftrekken of aftrekken (-
of -=
). Voorbeeld:
//remove Method1
allMethodsDelegate -= d1;
// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = allMethodsDelegate - d2;
Omdat gedelegeerdentypen worden afgeleid van System.Delegate
, kunnen de methoden en eigenschappen die door die klasse zijn gedefinieerd, worden aangeroepen voor de gemachtigde. Als u bijvoorbeeld het aantal methoden in de aanroeplijst van een gemachtigde wilt vinden, kunt u het volgende schrijven:
int invocationCount = d1.GetInvocationList().GetLength(0);
Gemachtigden met meer dan één methode in hun aanroeplijst afgeleid van MulticastDelegate, een subklasse van System.Delegate
. De bovenstaande code werkt in beide gevallen omdat beide klassen ondersteuning bieden GetInvocationList
.
Multicast-gemachtigden worden uitgebreid gebruikt bij het verwerken van gebeurtenissen. Gebeurtenisbronobjecten verzenden gebeurtenismeldingen naar ontvangerobjecten die zijn geregistreerd om die gebeurtenis te ontvangen. Voor het registreren van een gebeurtenis maakt de ontvanger een methode die is ontworpen om de gebeurtenis te verwerken, maakt vervolgens een gemachtigde voor die methode en geeft de gemachtigde door aan de gebeurtenisbron. De bron roept de gemachtigde aan wanneer de gebeurtenis plaatsvindt. De gedelegeerde roept vervolgens de methode voor gebeurtenisafhandeling aan op de ontvanger, waarbij de gebeurtenisgegevens worden bezorgd. Het type gemachtigde voor een bepaalde gebeurtenis wordt gedefinieerd door de gebeurtenisbron. Zie Gebeurtenissen voor meer informatie.
Het vergelijken van gemachtigden van twee verschillende typen die tijdens het compileren zijn toegewezen, resulteert in een compilatiefout. Als de gemachtigde instanties statisch van het type System.Delegate
zijn, is de vergelijking toegestaan, maar wordt onwaar geretourneerd tijdens runtime. Bijvoorbeeld:
delegate void Callback1();
delegate void Callback2();
static void method(Callback1 d, Callback2 e, System.Delegate f)
{
// Compile-time error.
//Console.WriteLine(d == e);
// OK at compile-time. False if the run-time type of f
// is not the same as that of d.
Console.WriteLine(d == f);
}