Meghatalmazottak és lambdák

A meghatalmazott olyan típust határoz meg, amely egy adott paraméterlistával és visszatérési típussal rendelkező metódusokra mutató hivatkozásokat jelöl. Olyan metódus (statikus vagy példány), amelynek paraméterlistája és visszatérési típusa megegyezik, hozzárendelhető egy ilyen típusú változóhoz, majd meghívható közvetlenül (a megfelelő argumentumokkal), vagy argumentumként átadható egy másik metódusnak, majd meghívható. Az alábbi példa a delegáltak használatát mutatja be.

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"));
    }
}
  • A public delegate string Reverse(string s); sor létrehoz egy delegált típusú metódust, amely egy sztringparamétert használ, majd visszaad egy sztringparamétert.
  • A static string ReverseString(string s) metódus, amely pontosan ugyanazzal a paraméterlistával és visszatérési típussal rendelkezik, mint a megadott delegált típus, implementálja a delegáltat.
  • A Reverse rev = ReverseString; sor azt mutatja, hogy a megfelelő delegált típusú változóhoz rendelhet metódust.
  • A Console.WriteLine(rev("a string")); sor bemutatja, hogyan hívhatja meg a delegáltat egy delegált típusú változóval.

A fejlesztési folyamat egyszerűsítése érdekében a .NET olyan delegált típusokat tartalmaz, amelyeket a programozók újra felhasználhatnak, és nem kell új típusokat létrehozniuk. Ezek a típusok Func<>és Predicate<>Action<> azok új delegálási típusok definiálása nélkül is használhatók. A három típus között van néhány különbség, amelyeknek a rendeltetésüknek megfelelően kell lenniük:

  • Action<> akkor használatos, ha műveletet kell végrehajtani a meghatalmazott argumentumait használva. A beágyazási metódus nem ad vissza értéket.
  • Func<> általában akkor használatos, ha egy átalakítás van a kezében, azaz a meghatalmazott argumentumait egy másik eredményre kell átalakítania. Jó példa az előrejelzésekre. A beágyazási metódus egy megadott értéket ad vissza.
  • Predicate<> akkor használatos, ha meg kell állapítania, hogy az argumentum megfelel-e a meghatalmazott feltételének. Megírható logikai értékként Func<T, bool>is, ami azt jelenti, hogy a metódus logikai értéket ad vissza.

A fenti példában most már átírhatjuk a delegáltat egyéni Func<> típus helyett. A program továbbra is pontosan ugyanúgy fog futni.

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

Ebben az egyszerű példában a metóduson kívül Main definiált metódus kissé feleslegesnek tűnik. .NET-keretrendszer 2.0 bevezette a névtelen meghatalmazottak fogalmát, amely lehetővé teszi a "beágyazott" meghatalmazottak létrehozását anélkül, hogy további típust vagy módszert kellene megadnia.

Az alábbi példában egy névtelen meghatalmazott a páros számokra szűri a listát, majd kinyomtatja őket a konzolon.

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

Mint látható, a delegált törzse csak egy kifejezéskészlet, mint bármely más meghatalmazott. De ahelyett, hogy külön definíció lenne, a módszer meghívásában List<T>.FindAll ad hoc módon vezettük be.

Azonban még ezzel a megközelítéssel is sok olyan kód van, amelyet el tudunk dobni. Itt kerülnek játékba a lambdakifejezések . A Lambda-kifejezéseket, röviden "lambdákat" a C# 3.0-ban vezették be a Language Integrated Query (LINQ) egyik alapvető építőelemeként. Ezek csak egy kényelmesebb szintaxis a meghatalmazottak használatához. Deklarálnak egy paraméterlistát és metódustörzset, de nem rendelkeznek saját formális identitással, kivéve, ha meghatalmazotthoz vannak rendelve. A meghatalmazottaktól eltérően közvetlenül hozzárendelhetők az eseményregisztráció jobb oldalán, vagy különböző LINQ-záradékokban és metódusokban.

Mivel a lambda kifejezés csak egy másik módszer a meghatalmazott megadására, a fenti mintát át kell írnunk, hogy egy lambda kifejezést használjunk névtelen meghatalmazott helyett.

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

Az előző példában a használt lambda kifejezés.i => i % 2 == 0 Ez is csak egy kényelmes szintaxis a meghatalmazottak használatához. A fedelek alatt az történik, ami a névtelen meghatalmazottal történik.

A lambdák szintén csak meghatalmazottak, ami azt jelenti, hogy probléma nélkül használhatók eseménykezelőként, ahogy az alábbi kódrészlet is mutatja.

public MainWindow()
{
    InitializeComponent();

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

Ebben += a kontextusban az operátor egy eseményre való feliratkozásra szolgál. További információ: Hogyan iratkozhat fel és iratkozhat le az eseményekről.

További olvasás és források