Delen via


Gemachtigden en lambdas

Een gemachtigde definieert een type dat verwijzingen vertegenwoordigt naar methoden met een bepaalde parameterlijst en retourtype. Een methode (statisch of exemplaar) waarvan de parameterlijst en retourtypeovereenkomst kunnen worden toegewezen aan een variabele van dat type, vervolgens rechtstreeks aangeroepen (met de juiste argumenten) of doorgegeven als een argument zelf aan een andere methode en vervolgens wordt aangeroepen. In het volgende voorbeeld ziet u het gebruik van gemachtigden.

using System;
using System.Linq;

public class Program
{
    public delegate string Reverse(string s);

    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Reverse rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}
  • De public delegate string Reverse(string s); regel maakt een gemachtigde type van een methode die een tekenreeksparameter gebruikt en retourneert vervolgens een tekenreeksparameter.
  • De static string ReverseString(string s) methode, die exact dezelfde parameterlijst heeft en het retourtype retourneert als het gedefinieerde type gedelegeerde, implementeert de gemachtigde.
  • De Reverse rev = ReverseString; regel laat zien dat u een methode kunt toewijzen aan een variabele van het bijbehorende gedelegeerdentype.
  • De Console.WriteLine(rev("a string")); regel laat zien hoe u een variabele van een gemachtigdentype gebruikt om de gemachtigde aan te roepen.

Om het ontwikkelingsproces te stroomlijnen, bevat .NET een set gedelegeerde typen die programmeurs opnieuw kunnen gebruiken en geen nieuwe typen hoeven te maken. Deze typen zijn Func<>en Action<>Predicate<>kunnen worden gebruikt zonder nieuwe gedelegeerdentypen te hoeven definiëren. Er zijn enkele verschillen tussen de drie typen die te maken hebben met de manier waarop ze bedoeld waren om te worden gebruikt:

  • Action<> wordt gebruikt wanneer er een actie moet worden uitgevoerd met behulp van de argumenten van de gemachtigde. De methode die wordt ingekapseld, retourneert geen waarde.
  • Func<> wordt meestal gebruikt wanneer u een transformatie bij de hand hebt, dat wil gezegd, moet u de argumenten van de gemachtigde omzetten in een ander resultaat. Projecties zijn een goed voorbeeld. De methode die wordt ingekapseld, retourneert een opgegeven waarde.
  • Predicate<> wordt gebruikt wanneer u moet bepalen of het argument voldoet aan de voorwaarde van de gemachtigde. Het kan ook worden geschreven als een Func<T, bool>, wat betekent dat de methode een Booleaanse waarde retourneert.

We kunnen nu ons bovenstaande voorbeeld nemen en opnieuw schrijven met behulp van de Func<> gemachtigde in plaats van een aangepast type. Het programma blijft exact hetzelfde uitvoeren.

using System;
using System.Linq;

public class Program
{
    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Func<string, string> rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}

Voor dit eenvoudige voorbeeld lijkt het een beetje overbodig om een methode te hebben die buiten de Main methode is gedefinieerd. .NET Framework 2.0 heeft het concept van anonieme gemachtigden geïntroduceerd, waarmee u 'inline'-gemachtigden kunt maken zonder dat u een extra type of methode hoeft op te geven.

In het volgende voorbeeld filtert een anonieme gemachtigde een lijst naar alleen de even getallen en drukt deze vervolgens af op de console.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(
          delegate (int no)
          {
              return (no % 2 == 0);
          }
        );

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

Zoals u ziet, is de hoofdtekst van de gemachtigde slechts een set expressies, zoals elke andere gemachtigde. Maar in plaats van dat het een afzonderlijke definitie is, hebben we het ad-hoc geïntroduceerd in onze aanroep naar de List<T>.FindAll methode.

Zelfs met deze aanpak is er echter nog steeds veel code die we kunnen weggooien. Hier komen lambda-expressies in het spel. Lambda-expressies, of gewoon 'lambdas', zijn in C# 3.0 geïntroduceerd als een van de belangrijkste bouwstenen van Language Integrated Query (LINQ). Ze zijn slechts een handigere syntaxis voor het gebruik van gemachtigden. Ze declareren een lijst met parameters en de hoofdtekst van de methode, maar hebben geen eigen identiteit, tenzij ze zijn toegewezen aan een gemachtigde. In tegenstelling tot gemachtigden kunnen ze rechtstreeks worden toegewezen als de rechterkant van de gebeurtenisregistratie of in verschillende LINQ-componenten en -methoden.

Omdat een lambda-expressie een andere manier is om een gemachtigde op te geven, moeten we het bovenstaande voorbeeld opnieuw kunnen schrijven om een lambda-expressie te gebruiken in plaats van een anonieme gemachtigde.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(i => i % 2 == 0);

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

In het voorgaande voorbeeld wordt i => i % 2 == 0de gebruikte lambda-expressie gebruikt. Nogmaals, het is slechts een handige syntaxis voor het gebruik van gemachtigden. Wat er onder de covers gebeurt, is vergelijkbaar met wat er gebeurt met de anonieme gemachtigde.

Nogmaals, lambdas zijn alleen gemachtigden, wat betekent dat ze zonder problemen kunnen worden gebruikt als een gebeurtenis-handler, zoals het volgende codefragment illustreert.

public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) =>
    {
        this.Title = "Loaded";
    };
}

De += operator in deze context wordt gebruikt om u te abonneren op een gebeurtenis. Zie Hoe u zich kunt abonneren op en afmelden voor gebeurtenissen voor meer informatie.

Meer informatie en bronnen