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 ombud objektorienterade, skriver säkra och säkra. Typen av ombud definieras av namnet på ombudet. 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 ombudsobjekt konstrueras normalt genom att ange namnet på den metod som ombudet ska omsluta, eller med ett lambda-uttryck. När ett ombud har instansierats på det här sättet kan det anropas. Om du anropar ett ombud anropas metoden som är kopplad till den delegerade instansen. Parametrarna som skickas till ombudet av anroparen skickas till metoden och returvärdet, om det finns några, från metoden returneras till anroparen av ombudet. 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");

Ombudstyper härleds från Delegate klassen 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. På så sätt kan en metod 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 har slutförts. 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 återanrop är att definiera en anpassad jämförelsemetod och skicka ombudet till en sorteringsmetod. Det gör att anroparens kod kan bli en del av sorteringsalgoritmen. I följande exempelmetod används Del 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 ovan till den metoden:

MethodWithCallback(1, 2, handler);

och ta emot följande utdata till konsolen:

The number is: 3

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

När ett ombud konstrueras för att omsluta en instansmetod refererar ombudet till både instansen och metoden. Ett ombud har ingen kunskap om instanstypen förutom den metod som den omsluter, så ett ombud kan referera till alla typer av objekt så länge det finns en metod för objektet som matchar ombudets signatur. När ett ombud konstrueras för att omsluta 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 som DelegateMethod visades tidigare har vi nu tre metoder som kan omslutas av en Del instans.

Ett ombud kan anropa mer än en metod när det anropas. Detta kallas 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;

I det här läget allMethodsDelegate finns 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 genererar ett undantag som inte fångas i metoden skickas det undantaget till anroparen för ombudet och inga efterföljande metoder i anropslistan anropas. Om ombudet har ett returvärde och/eller utparametrar returneras returvärdet och parametrarna för den senaste metoden som anropades. 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);

Ombud med mer än en metod i listan över anrop härleds från MulticastDelegate, vilket är en underklass av System.Delegate. Koden ovan fungerar i båda fallen eftersom båda klasserna stöder GetInvocationList.

Multicast-ombud används i stor utsträckning i händelsehantering. Händelsekällans objekt skickar händelsemeddelanden till mottagarobjekt som har 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. Ombudstypen för en viss händelse definieras av händelsekällan. Mer information finns i Händelser.

Om du jämför ombud av två olika typer som tilldelats vid kompileringstid resulterar det i ett kompileringsfel. Om de delegerade instanserna är statiskt av typen System.Delegatetillåts jämförelsen, men 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