System.Delegate en het delegate trefwoord

Vorige

In dit artikel worden de klassen in .NET behandeld die gemachtigden ondersteunen en hoe deze worden toegewezen aan het delegate trefwoord.

Gedelegeerdentypen definiëren

Laten we beginnen met het trefwoord 'gemachtigde', want dat is voornamelijk wat u gaat gebruiken wanneer u met gemachtigden werkt. De code die de compiler genereert wanneer u het delegate trefwoord gebruikt, wordt toegewezen aan methode-aanroepen die leden van de Delegate en MulticastDelegate klassen aanroepen.

U definieert een type gemachtigde met behulp van syntaxis die vergelijkbaar is met het definiëren van een methodehandtekening. U hoeft alleen het delegate trefwoord aan de definitie toe te voegen.

Laten we de methode List.Sort() blijven gebruiken als voorbeeld. De eerste stap bestaat uit het maken van een type voor de vergelijkingsdelegen:

// From the .NET Core library

// Define the delegate type:
public delegate int Comparison<in T>(T left, T right);

De compiler genereert een klasse die is afgeleid van System.Delegate die overeenkomt met de gebruikte handtekening (in dit geval een methode die een geheel getal retourneert en twee argumenten heeft). Het type van die gemachtigde is Comparison. Het Comparison type gemachtigde is een algemeen type. Zie hier voor meer informatie over generics.

U ziet dat de syntaxis kan lijken alsof er een variabele wordt gedeclareert, maar dat de syntaxis daadwerkelijk een type declareren. U kunt gemachtigdentypen definiëren binnen klassen, rechtstreeks binnen naamruimten of zelfs in de globale naamruimte.

Notitie

Het rechtstreeks declareren van gedelegeerde typen (of andere typen) in de globale naamruimte wordt niet aanbevolen.

De compiler genereert ook handlers voor toevoegen en verwijderen voor dit nieuwe type, zodat clients van deze klasse methoden kunnen toevoegen aan en verwijderen uit de aanroeplijst van een exemplaar. De compiler dwingt af dat de handtekening van de methode die wordt toegevoegd of verwijderd overeenkomt met de handtekening die wordt gebruikt bij het declareren van de methode.

Instanties van gemachtigden declareren

Nadat u de gemachtigde hebt gedefinieerd, kunt u een exemplaar van dat type maken. Net als alle variabelen in C# kunt u geen gemachtigden rechtstreeks in een naamruimte of in de globale naamruimte declareren.

// inside a class definition:

// Declare an instance of that type:
public Comparison<T> comparator;

Het type van de variabele is Comparison<T>, het gedelegeerdentype dat eerder is gedefinieerd. De naam van de variabele is comparator.

Dat codefragment hierboven heeft een lidvariabele in een klasse gedeclareerd. U kunt ook gemachtigdenvariabelen declareren die lokale variabelen of argumenten zijn voor methoden.

Gemachtigden aanroepen

U roept de methoden aan die zich in de aanroeplijst van een gemachtigde bevinden door die gemachtigde aan te roepen. Binnen de Sort() methode roept de code de vergelijkingsmethode aan om te bepalen welke volgorde moet worden gebruikt om objecten te plaatsen:

int result = comparator(left, right);

In de bovenstaande regel roept de code de methode aan die is gekoppeld aan de gemachtigde. U behandelt de variabele als een methodenaam en roept deze aan met behulp van de syntaxis van de normale methode-aanroep.

Deze coderegel maakt een onveilige aanname: er is geen garantie dat er een doel is toegevoegd aan de gemachtigde. Als er geen doelen zijn gekoppeld, zou de bovenstaande regel ertoe leiden dat er een NullReferenceException gegooid wordt. De idiomen die worden gebruikt om dit probleem op te lossen, zijn ingewikkelder dan een eenvoudige null-controle en worden verderop in deze reeks behandeld.

Aanroepdoelen toewijzen, toevoegen en verwijderen

Dit is hoe een type gedelegeerde wordt gedefinieerd en hoe gemachtigde instanties worden gedeclareerd en aangeroepen.

Ontwikkelaars die de List.Sort() methode willen gebruiken, moeten een methode definiëren waarvan de handtekening overeenkomt met de definitie van het gemachtigde type en deze toewijzen aan de gemachtigde die wordt gebruikt door de sorteermethode. Met deze toewijzing wordt de methode toegevoegd aan de aanroeplijst van dat gemachtigde object.

Stel dat u een lijst met tekenreeksen wilt sorteren op lengte. Uw vergelijkingsfunctie kan het volgende zijn:

private static int CompareLength(string left, string right) =>
    left.Length.CompareTo(right.Length);

De methode wordt gedeclareerd als een privémethode. Dat is prima. Mogelijk wilt u niet dat deze methode deel uitmaakt van uw openbare interface. Deze kan nog steeds worden gebruikt als vergelijkingsmethode wanneer deze is gekoppeld aan een gemachtigde. De aanroepende code bevat deze methode die is gekoppeld aan de doellijst van het gedelegeerde-object en heeft er toegang toe via die gemachtigde.

U maakt die relatie door die methode door te geven aan de List.Sort() methode:

phrases.Sort(CompareLength);

U ziet dat de naam van de methode wordt gebruikt, zonder haakjes. Als u de methode als argument gebruikt, vertelt de compiler dat de verwijzing naar de methode moet worden geconverteerd naar een verwijzing die kan worden gebruikt als een gemachtigde aanroepdoel en deze methode als een aanroepdoel koppelt.

U kunt ook expliciet zijn geweest door een variabele van het type Comparison<string> te declareren en een toewijzing uit te voeren:

Comparison<string> comparer = CompareLength;
phrases.Sort(comparer);

In gebruik waarbij de methode die wordt gebruikt als een gemachtigdedoel een kleine methode is, is het gebruikelijk om de syntaxis van de lambda-expressie te gebruiken om de toewijzing uit te voeren:

Comparison<string> comparer = (left, right) => left.Length.CompareTo(right.Length);
phrases.Sort(comparer);

Het gebruik van lambda-expressies voor gedelegeerde doelen wordt meer behandeld in een latere sectie.

In het voorbeeld Sort() wordt doorgaans één doelmethode aan de gemachtigde gekoppeld. Gedelegeerde objecten ondersteunen echter aanroeplijsten met meerdere doelmethoden die zijn gekoppeld aan een gedelegeerde-object.

Klassen Delegeren en MulticastDelegate

De hierboven beschreven taalondersteuning biedt de functies en ondersteuning die u doorgaans nodig hebt om met gemachtigden te werken. Deze functies zijn gebaseerd op twee klassen in het .NET Core-framework: Delegate en MulticastDelegate.

De System.Delegate klasse en de afzonderlijke directe subklasse, System.MulticastDelegatebieden de frameworkondersteuning voor het maken van gemachtigden, het registreren van methoden als gedelegeerde doelen en het aanroepen van alle methoden die zijn geregistreerd als een gemachtigdedoel.

Interessant is dat de System.Delegate en System.MulticastDelegate klassen zelf geen gedelegeerde typen zijn. Ze bieden wel de basis voor alle specifieke gedelegeerdentypen. Hetzelfde taalontwerpproces vereist dat u geen klasse kunt declareren die is afgeleid van Delegate of MulticastDelegate. De C#-taalregels verbieden dit.

In plaats daarvan maakt de C#-compiler exemplaren van een klasse die is afgeleid van MulticastDelegate wanneer u het sleutelwoord C#-taal gebruikt om gedelegeerdentypen te declareren.

Dit ontwerp heeft zijn wortels in de eerste release van C# en .NET. Een doel van het ontwerpteam was ervoor te zorgen dat de taal de veiligheid van het type afdwingde bij het gebruik van gemachtigden. Dit betekende dat gedelegeerden werden aangeroepen met het juiste type en het juiste aantal argumenten. En dat elk retourtype correct werd aangegeven tijdens het compileren. Gedelegeerden maakten deel uit van de .NET-release 1.0, die voorheen algemeen was.

De beste manier om dit type veiligheid af te dwingen, was voor de compiler om de concrete gedelegeerde klassen te maken die de gebruikte methodehandtekening vertegenwoordigden.

Hoewel u geen afgeleide klassen rechtstreeks kunt maken, gebruikt u de methoden die voor deze klassen zijn gedefinieerd. Laten we de meest voorkomende methoden doorlopen die u gaat gebruiken wanneer u met gemachtigden werkt.

Het eerste, belangrijkste feit is dat elke gedelegeerde waarmee u werkt, is afgeleid van MulticastDelegate. Een multicastdelegatie betekent dat meer dan één methodedoel kan worden aangeroepen bij het aanroepen van een gemachtigde. Het oorspronkelijke ontwerp beschouwde een onderscheid te maken tussen gemachtigden waarbij slechts één doelmethode kon worden gekoppeld en aangeroepen, en gemachtigden waarbij meerdere doelmethoden konden worden gekoppeld en aangeroepen. Dat onderscheid bleek in de praktijk minder nuttig te zijn dan oorspronkelijk gedacht. De twee verschillende klassen zijn al gemaakt en zijn sinds de eerste openbare release in het framework opgenomen.

De methoden die u het meest gebruikt met gemachtigden zijn Invoke() en BeginInvoke() / EndInvoke(). Invoke() roept alle methoden aan die zijn gekoppeld aan een bepaalde gemachtigde instantie. Zoals u hierboven hebt gezien, roept u doorgaans gemachtigden aan met behulp van de syntaxis van de methode-aanroep voor de gemachtigdevariabele. Zoals u verderop in deze reeks ziet, zijn er patronen die rechtstreeks met deze methoden werken.

Nu u de syntaxis van de taal en de klassen hebt gezien die gemachtigden ondersteunen, gaan we kijken hoe sterk getypte gemachtigden worden gebruikt, gemaakt en aangeroepen.

Volgende