Grundkurs i C-Sharp - Delegater
Förord
Det kommer en tid då man som programmerare skulle vilja att när man anropar en metod på ett objekt så är det inte alltid en given implementation av den metoden som anropas utan att det kunde styras på något sätt. Om du har funnit dig själv i denna situation någon gång så tycker jag du skall läsa vidare och glädjas över att det faktiskt inte är omöjligt. Denna artikel är även relevant för den som vill lära sig hur händelser i .NET fungerar då de till största delen bygger på delegater. För de som har arbetat med C/C++ kan jag nämna att delegater är som funktions pekare fast med en del skillnader som ni förstår om ni läser vidare.Innehåll
»»
Delegate
Det första vi skall behandla om delegater är att det finns ett nyckelord som man använder för att skapa sig en sådan och givetvis är det delegate. Nu när vi har detta ur världen kan vi ta oss en titt på vad en delegat faktiskt är.Givetvis gör vi detta enklast genom att betrakta ett kort exempel så som det nedan.
class Customers
{
public Customers()
{
}
public void Save()
{
// Spara ut kundinformationen till exempelvis
// en databas.
}
}
Vi har är skapar oss en klass som heter Customers. Denna klass lagrar information om kunderna i ett program (t.ex. ett faktureringsprogram). Vi har lagt till en metod Save() för att spara ut kunderna till en databas.
Under utvecklingen av vårt program bestämmer vi oss för att vi vill implementera kod som loggar aktiviteter som vårt program gör under drift, men vad vi inte vill göra är att låsa oss till en form av lagringsformat (xml, textfil, databas, windows aktivitetshanterare etc.) för våra aktiviteter.
Hur löser vi då detta? Vi skulle kunna implementera olika typer av funktioner för att spara aktiviteterna till olika format, men detta skulle snabbt kunna bli en hel del och det kan tyckas dumt eftersom att vi t.ex. låser oss vid ett fast antal format.
Genom att använda oss av en delegat, som kan liknas vid en referens till en metod, så kan vi enkelt lösa vårt problem. En delegat beskriver hur den metod vi vill anropa skall se ut, i form av in parametrar och retur värde, men inte någon implementation.
I följande exempel har vi lagt till en publik delegat i vår Customers klass som förväntar sig en sträng som in parameter (kan användas för att ange vilken fil eller databas tabell som skall användas) och att den inte returnerar något värde.
class Customers
{
public delegate void LogHandler(string s);
public Customers()
{
}
public void Save()
{
// Spara ut kundinformationen till exempelvis
// en databas.
}
}
För att kunna använda vår delegat för att genomföra en loggning av en aktivitet måste vi bygga ut vår Save() method så att den kan ta emot en LogHandler delegat som parameter.
class Customers
{
public delegate void LogHandler(string s);
public Customers()
{
}
public void Save(LogHandler logger)
{
// Spara ut kundinformationen till exempelvis
// en databas.
}
}
Innan vi nu kan använda oss av vår log delegat får metoden Save() så måste vi ta en sak under omtanke och det är att användaren av Customers klassen kanske inte har angett någon LogHandler metod eftersom man inte vill logga aktiviteter. Skulle vi då försöka anropa får LogHanterare via objektet logger så skulle vi få ett fel. Vad vi måste göra är att först kontrollera så att objektet logger inte är null och sen anropa metoden.
class Customers
{
public delegate void LogHandler(string s);
public Customers()
{
}
public void Save(LogHandler logger)
{
if( logger != null )
logger(“Börjar med att spara kunder.”);
// Spara ut kundinformationen till exempelvis
// en databas.
If( logger != null )
logger(“Klar med att spara kunder.”);
}
}
Vår Customers klass kan nu använda sig av aktivitets loggaren om en sådan har till handa hålligts annars bryr den sig inte om det.
Nedan visas ett exempel på hur klassen Customers kan användas utan en metod för att logga aktiviteter i klassen.
// Metod 1. Utan aktivitets loggare.
class Test
{
public static void Main()
{
Customers c = new Customers();
c.Save(null);
}
}
Detta exempel kommer inte att skriva ut log texterna någonstans då logger kommer att vara null när programmet körs.
Nästa exempel visar hur man använder klassen Customers tillsammans med en metod för att logga aktiviteterna. I detta fallet använder vi oss av en enkel log funktion för att skriva ut aktiviteterna i ett kommandofönster.
//
// Metod 2. Med en aktivitets loggare.
//
class Test
{
void Text(string s)
{
// Skriv ut logtexten i ett kommandofönster.
}
public static void Main()
{
Customers c = new MyClass();
c.LogHandler lh = new Customers.LogHandler(Text);
c.Save(lh);
}
}
Lägg market till att metoden Text(string s) har samma signature (in parametrar och returvärde) som den deklarerade delegaten i klassen Customers. Vi skapar sen en ny delegat lh av typen LogHandler och skickar med namnet på vå log metod som parameter. Denna delegat skickar vi sen med till vår Save() metod.
Per Persson
Jag har läst artikeln, men förstår inte vad skillnaden är mellan delegater och funktionspekare. Kan du precisera?
Andreas Håkansson
En delegat är ett object och är type-safe, samt att en delegat kan anropa både instans- och statiskametoder.