Delegates in C#
Soms willen we bij het oplossen van een probleem in code een bepaalde functie uitvoeren op basis van een voorwaarde of situatie. Je kan dan via if-then-else of een switch bepalen welke functie je uitvoert. Als er een nieuwe voorwaarde komt, moet je deze statements uitbreiden, dat is een nadeel. Als alternatief kan je interfaces gebruiken, maar deze zijn bedoeld voor hele klassen en niet alleen functies. Een andere oplossing die je kan toepassen, zijn delegates.
Een delegate definieer je eerst in ergens in je code, alsof je een method in een interface definieert:
private delegate string DoeIetsMetTekst(string tekst);
Nu kan je een functie aanroepen en een functie als argument meegeven die iets doet:
private static string BewerkString(string tekst, DoeIetsMetTekst bewerking)
{
var nieuweTekst = bewerking(tekst);
return nieuweTekst;
}
Hierboven is bewerking een delegate en kan dus worden uitgevoerd als een functie. Welke functie dat is, dat kan later worden bepaald in de code. Nu hoef je alleen een functie te maken met dezelfde parameters en type als DoeIetsMetTekst en deze mee te geven aan BewerkString:
static void Main(string[] args)
{
var tekst = "Ik voer enkele bewerkingen uit op deze tekst.";
DoeIetsMetTekst bewerking = naarHoofdletters;
var r = BewerkString(tekst, bewerking);
Console.WriteLine(r);
}
private static string naarHoofdletters(string tekst)
{
return tekst.ToUpper();
}
Het resultaat is:
IK VOER ENKELE BEWERKINGEN UIT OP DEZE TEKST.
Mogelijk wil je de tekst omkeren, in bepaalde situaties, en daarvoor kan je ook een functie schrijven en aanroepen:
DoeIetsMetTekst bewerking = keerTekstOm;
var r = BewerkString(tekst, bewerking);
private static string keerTekstOm(string tekst)
{
char[] array = tekst.ToCharArray();
Array.Reverse(array);
var nieuweTekst = new String(array);
return nieuweTekst;
}
Resultaat:
.tsket ezed po tiu negnikreweb elekne reov kI
Handig van delegates is dat je meerdere methodes in 1 delegate kunt zetten:
DoeIetsMetTekst bewerking = keerTekstOm;
bewerking += naarHoofdletters;
Resultaat:
IK VOER ENKELE BEWERKINGEN UIT OP DEZE TEKST.
Alle functies die zijn toegevoegd aan de delegate bewerking worden uitgevoerd. In mijn voorbeeld pas ik het argument niet aan, maar maak ik een nieuwe string. Daarom wordt alleen het resultaat van naarHoofdletters met de originele tekst teruggegeven. Als ik een reference parameter meegeef (zoals een class), dan kan ik de parameter bewerken en die bewerkte parameter wordt gebruikt door de volgende functie. Een string is echter geen reference parameter an sich. Als ik dat aanpas en ik zorg ervoor dat er geen nieuwe variabele wordt teruggegeven, dan worden beide bewerkingen zichtbaar:
private delegate void DoeIetsMetTekst(ref string tekst);
//...
var r = BewerkString(ref tekst, bewerking);
//...
private static void naarHoofdletters(ref string tekst)
{
tekst = tekst.ToUpper();
}
private static void keerTekstOm(ref string tekst)
{
char[] array = tekst.ToCharArray();
Array.Reverse(array);
var nieuweTekst = new String(array);
tekst = nieuweTekst;
}
private static string BewerkString(ref string tekst, DoeIetsMetTekst bewerking)
{
bewerking(ref tekst);
return tekst;
}
Resultaat:
.TSKET EZED PO TIU NEGNIKREWEB ELEKNE REOV KI
Bovenstaande voorbeelden zijn wat onwaarschijnlijk en zal je niet snel toepassen. Een meer voor de hand liggende use case is wanneer je een klasse hebt gemaakt met bepaalde methodes, die aangeroepen kunnen worden door andere code geschreven door bijvoorbeeld collega's, in dezelfde solution. Stel je een event-model voor, bijvoorbeeld, waarin jouw functie altijd aangeroepen wordt als een soort event-listener, maar wĂĄt er gebeurt, afhankelijk is van de Delegate die wordt meegestuurd.
Delegates en interfaces lijken op elkaar, zie https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ms173173(v=vs.100). Er zijn ook meerdere oplossingen voor hetzelfde probleem en bovenstaande zou ook via interfaces opgepakt kunnen worden, hoewel in dit geval er minder code nodig is, die wellicht wat overzichtelijker is en beter te beheren. Hoe dan ook zijn delegates een handig hulpmiddel.