Dela via


Använda ombud (C#-programmeringsguide)

Ett ombud är en typ som på ett säkert sätt kapslar in en metod, ungefär som en funktionspekare i C och C++. Till skillnad från C-funktionspekare är delegater objektorienterade, typ-säkra och säkra. I följande exempel deklareras ett ombud med namnet Callback som kan kapsla in en metod som tar en sträng som argument och returnerar void:

public delegate void Callback(string message);

Ett delegatobjekt konstrueras normalt genom att specificera namnet på metoden som delegaten omsluter, eller med ett lambda-uttryck. En delegerad kan anropas när den har instansierats på det här sättet. Om du anropar ett ombud anropas metoden som är kopplad till den delegerade instansen. Parametrarna som skickas till ombudet av anroparen skickas till metoden. Ombudet returnerar returvärdet, om det finns något, från metoden. Till exempel:

// 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");

Delegattyper härleds från klassen Delegate i .NET. Ombudstyper är förseglade, de kan inte härledas från och det går inte att härleda anpassade klasser från Delegate. Eftersom den instansierade delegaten är ett objekt kan det skickas som ett argument eller tilldelas till en egenskap. En metod kan acceptera ett ombud som en parameter och anropa ombudet vid ett senare tillfälle. Detta kallas för en asynkron motringning och är en vanlig metod för att meddela en anropare när en lång process slutförs. När ett ombud används på det här sättet behöver koden som använder ombudet inte någon kunskap om implementeringen av den metod som används. Funktionen liknar inkapslingsgränssnitten.

En annan vanlig användning av callback-funktioner är att definiera en specialanpassad jämförelsemetod och överföra delegeringen till en sorteringsmetod. Det gör att anroparens kod kan bli en del av sorteringsalgoritmen. I följande exempelmetod används Callback typen som en parameter:

public static void MethodWithCallback(int param1, int param2, Callback callback)
{
    callback("The number is: " + (param1 + param2).ToString());
}

Du kan sedan skicka ombudet som skapades i föregående exempel till den metoden:

MethodWithCallback(1, 2, handler);

Och ta emot följande utdata till konsolen:

The number is: 3

MethodWithCallback behöver inte anropa konsolen direkt– den behöver inte utformas med en konsol i åtanke. Det som MethodWithCallback gör är att förbereda en sträng och skicka strängen till en annan metod. En delegerad metod kan använda valfritt antal parametrar.

När en delegering konstrueras för att omsluta en instansmetod refererar delegeringen till både instansen och metoden. Ett ombud har ingen kunskap om instanstypen förutom den metod som den omsluter. Ett ombud kan referera till vilken typ av objekt som helst så länge det finns en metod för objektet som matchar delegatsignaturen. När en delegat konstrueras för att använda en statisk metod refererar den bara till metoden. Tänk på följande deklarationer:

public class MethodClass
{
    public void Method1(string message) { }
    public void Method2(string message) { }
}

Tillsammans med den statiska DelegateMethod som visades tidigare, har vi nu tre metoder som du kan omsluta i en Callback instans.

En delegat kan anropa flera metoder när den anropas, vilket kallas för multicasting. Om du vill lägga till en extra metod i ombudets lista över metoder – listan över anrop – behöver du bara lägga till två ombud med hjälp av tilläggs- eller tilläggstilldelningsoperatorerna (+eller +=). Till exempel:

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;

Innehåller allMethodsDelegate tre metoder i listan över anrop –Method1 , Method2och DelegateMethod. De ursprungliga tre ombuden, d1, d2och d3, förblir oförändrade. När allMethodsDelegate anropas anropas alla tre metoderna i ordning. Om ombudet använder referensparametrar skickas referensen sekventiellt till var och en av de tre metoderna i tur och ordning, och eventuella ändringar med en metod visas för nästa metod. När någon av metoderna utlöser ett undantag som inte fångas i metoden skickas det undantaget till ombudets anropare. Inga efterföljande metoder i anropslistan anropas. Om ombudet har ett returvärde och/eller output-parametrar returnerar det returvärdet och parametrarna för den senaste metoden som anropats. Om du vill ta bort en metod från anropslistan använder du subtraktions- eller subtraktionstilldelningsoperatorerna (- eller -=). Till exempel:

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;

Eftersom ombudstyper härleds från System.Delegatekan de metoder och egenskaper som definierats av den klassen anropas på ombudet. Om du till exempel vill hitta antalet metoder i ombudets anropslista kan du skriva:

int invocationCount = d1.GetInvocationList().GetLength(0);

Delegater med mer än en metod i sin anropslista härleds från MulticastDelegate, vilka är en subklass av System.Delegate. Föregående kod fungerar i båda fallen eftersom båda klasserna stöder GetInvocationList.

Multicast-delegater används i stor utsträckning i händelsehantering. Händelsekällans objekt skickar händelsemeddelanden till mottagarobjekt som registrerats för att ta emot händelsen. För att registrera sig för en händelse skapar mottagaren en metod som är utformad för att hantera händelsen, skapar sedan ett ombud för den metoden och skickar ombudet till händelsekällan. Källan anropar ombudet när händelsen inträffar. Ombudet anropar sedan händelsehanteringsmetoden på mottagaren och levererar händelsedata. Händelsekällan definierar ombudstypen för en viss händelse. Mer information finns i Händelser.

Att jämföra delegater av två olika typer som tilldelats under kompilering resulterar i ett kompileringsfel. Om de delegerade instanserna är av typen System.Delegate statiskt, tillåts jämförelsen, men den returnerar false vid körning. Till exempel:

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);
}

Se även