Delegates og Events

Tags:    c#
Skrevet af Bruger #2730 @ 09.05.2005
Denne artikel omhandler delegates og events samt hvordan de hænger sammen.

Hvad er events


Events er beskeder der sker i et system når der sker en bestemt hændelse. En bestemt hændelse kan for eksempel være når brugeren trykker på en knap eller når brugeren laver et flueben i en checkbox. Alle disse hændelser har det til fælles at de tilbyder en event. Det betyder at jeg som programmør kan sige til knappen eller til checkboksen at jeg grene vil have noget specielt kode kørt når denne event bliver udført. Een ting er at en knap tilbyder en event, noget andet er at der skal også noget til at håndtere når der så er blevet trykket på knappen, dette er en eventhandler. En eventhandler indeholder kode der bliver eksekveret når eventen bliver "raised". Hvis man har forsøgt sig med at lave en simpel applikation i C# og tilføjet en knap til sin form, og i design mode dobbeltklikket på den, så kommer man ned i koden hvor man kan skrive hvad der skal ske når der bliver trykket på knappen, dette er rent faktisk event handleren til knappens "Click" event. Mere om events efter delegates.

Hvad er delegates?


Delegates er essentielle i forbindelse med events, det er i bund og grund type-sikre funktionspointere, der tillader dig at sende en reference til en metode og eksekvere denne metode, uden direkte at kalde metoden. Når man laver en delegate skal den have samme signatur som den metode den skal eksekvere (samme parametre og samme return type).
Fold kodeboks ind/udKode 

Ovenstående er en simpel delegate der forventer en metode der tager to integers som parametre og returnerer et integer. Når man så skal have kaldt en delegate skal man erklære en ny instans af delegaten og tildele den navnet på den metode der skal eksekveres.
Fold kodeboks ind/udKode 

Når først vores delegate er instantieret kan den kaldes som alle andre metoder, den skal blot have de samme parametre med som delegaten (og metoden) kræver.

Delegates og events


Når man erklærer en event benyttes event nøgleordet, ligesom man ved erklæring af delegates benytter delegate nøgleordet. At oprette en event er direkte knyttet til delegates i C# skal man direkte angive hvilken delegate ens event vil benytte. Dette ser således ud:
Fold kodeboks ind/udKode 

Som vi kan se er vores event af typen multiplyDelegate, som er nødvendigt for at en event. Hvis vi et sted i vores kode skal kalde vores event (raise den) kan vi blot kalde vores event.
Fold kodeboks ind/udKode 

For også at få noget kode eksekveret når denne event opstår skal vi også have en eventhandler, ellers er der ingenting der "fanger" vores event. Der kan tildeles en eller flere event handlere til den samme event. Når vi så har lavet vores eventhandler skal vi associere vores event med vores eventhandler, ellers sker der ingenting. For at associere eventen til event handleren laver vi en ny instans af vores delegate og benytter += operatoren til at lave selve associationen, += operatoren kan også bruges til at lave en association til en allerede eksisterende delegate, ligeledes kan -= operatoren benyttes til at fjerne associationen. Indtil nu har vi benyttet simple multiplicerings methoder, nu laver vi et lille objekt der kan lidt mere, et bil objekt.
Fold kodeboks ind/udKode 

En simpel klasse der repræsenterer en bil. Som man kan se er der en delegate der hedder StartCar og en event der hedder CarStarted. For at indikere at vores bil er started, kalder vi vores event CarStarted i vores constructor, på denne måde starter vores bil når vi instantierer te nyt Car objekt.
Fold kodeboks ind/udKode 

For at kunne "lytte" på vores event skal vi også have lavet en eventhandler der håndterer vores event, denne eventhandler kan enten laves i en ekstern klasse (på den måde kan man sende informationer til alle afkroge af sit program) i dette eksempel har jeg valgt at lave eventhandleren direkte i min constructor, for at holde det mere overskueligt.
Fold kodeboks ind/udKode 

Som det kan ses har jeg indsat associationen til min eventhandler før jeg kalder min event, hvis ikke jeg gjorde dette ville jeg rent faktisk aldrig få en event, da kaldet ville ske før jeg havde associeret en event handler med min event. I Visual Studio (VS) er det nemt at lave dette, man skriver sin event samt += operatoren, så laver VS en lille informationsboks, hvor der står at hvis man trykker på tab, så implementerer den eventhandleren for en, nemmere kan det vist ikke blive. Og som vi kan se så har vores eventhandler (Car_CarStarted) samme signatur som vores delegate. Skulle jeg teste ovenstående eksempel ville jeg lave en instans af min Car klasse.
Fold kodeboks ind/udKode 

Hvorefter min eventhandler ville reagere på eventen der bliver raised i min constructor og skrive følgende til min output konsol:
Fold kodeboks ind/udKode 


Multiple event handlere


Der er ikke noget i vejen for at man kan bruge den samme eventhandler til flere events, det er blot et spørgsmål om at lave flere associeringer. Et eksempel på dette kunne fx, være med en button i en form
Fold kodeboks ind/udKode 



Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (7)

User
Bruger #6139 @ 09.05.05 16:06
Hvad er fordelen ved at benytte Events istedet for at bruge delegaten direkte? Kunne man med andre ord have undladt eventnøgleordet? Det gør jeg på et tidspunkt, men jeg ved ikke om det er galt, det virker udemærket!
User
Bruger #2730 @ 11.05.05 08:25
Jeg synes fordelen ved at bruge events er at jeg kan "lytte" på dem og lade dem alarmere mig, hvis der sker noget i mit program, det vil sige det er en "push" i stedet for en "pull"
User
Bruger #6139 @ 11.05.05 11:42
Fold kodeboks ind/udKode 
User
Bruger #6139 @ 11.05.05 11:47
Ja jeg kan ikke lige finde ud af at indsætte kode, men...

Jeg er ny i Delegate afdelingen og da jeg så læste din artikel opdagede jeg at jeg laver det på den måde jeg lige har postet. Altså hvor jeg definerer min delegate, herefter opretter jeg et nyt objekt af denne type.

Resultatet bliver at hvis jeg vil sende beskeder skriver jeg bare fx:

newItemSelected(this)

men jeg bruger ikke noget event nøgle ord?

Det virker selvfølgelig men jeg ville lige forhøre mig hos kodeguruen Brian Hvarregaard
User
Bruger #2730 @ 11.05.05 21:26
Det er også korrekt! men det er ikke en event. Det du laver er "bare" en delegate, og de er også utroligt nyttige. Men du er stadig afhængig af at du selv skal kalde din delegate: newItemSelected(this); Hvad nu hvis man forestillede sig at din metode blev kaldt "automatisk" dvs. at når der skete noget i dit program så blev din event kaldt, og alle der "abonnerer" på den event kunne sætte noget i gang, det er næste skridt. Hvis vi sammenligner med bilen i eksemplet, så kunne jeg godt have nøjet med en delegate, men hvad nu hvis der var andre eksterne interessenter der skulle vide når bilen startede.. fx. parkeringsvagten, eller lign. I dit eksempel skal du manuelt give parkeringsvagten besked ved at kalde en delegate eller lign. på ham, mens ved events kan parkeringsvagten "bare" lytte på bilens event, således at når bilen starter, skal bilen ikke gøre mere, end blot sige at "jeg starter" og så er det alle andre der skal tage stilling til det... håber det gav mening
User
Bruger #6139 @ 12.05.05 12:11
Det er det der er hele mit dilemma fordi jeg netop bruger newItemSelected fuldstændigt som en event uden nogensinde at bruge event nøgleordet.

Altså:

Inde i klassen ser det således ud:

public delegate void newItemSelectedEventHandler(treeViewHandler sender);
public newItemSelectedEventHandler newItemSelected

Udefra skriver jeg bare de berømte ord:

newItemSelected += new TreeViewHandler.newItemSelectedEventHandler([metoden der skal kaldes])

(hvor TreeViewHandler er min instans af treeViewHandler klassen)

jeg kan derfor melde så mange listeners på listen som jeg har lyst til med += operatoren.

Jeg ved ikke om det giver nogen mening det som jeg prøver at beskrive?
User
Bruger #2796 @ 12.07.05 09:09
Det var en god artikel. Den gav lige den sidste viden jeg manglede, og som jeg ikke har kunnet finde via google.
Du skal være logget ind for at skrive en kommentar.
t