Jordan Lee
Jordan LeeDevOps Engineer @ AGL Energy

Jak napisać w C# metody, które traktują lambdy jako parametry

Sprawdź, jak napisać w C# metodę, która potraktuje wyrażenie lambda jako parametr.
28.02.20203 min
Jak napisać w C# metody, które traktują lambdy jako parametry

Jeśli dopiero zaczynasz z C# albo ASP.NET Core, to pomimo, że metody, które używają wyrażeń lambda jako parametrów nie są dla Ciebie obce, możesz nie wiedzieć jak je samemu napisać. 


Weźmy na przykład metodę Configure z aplikacji ASP.NET Core:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if(env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}


Zauważ, w jaki sposób wyrażenie lambda jest przekazane jako argument w metodzie UseEndpoints(). Jak więc taką metodę napisać?

Wyrażenie lambda vs. delegaty

Zbadajmy najpierw różnice między nimi.

Delegat - zmienna będąca typem referencyjnym, która przechowuje referencję do danej metody. 

Wyrażenie lambda - w C# jest używane jako anonimowa funkcja, z tą różnicą, że w lambdach nie trzeba określać typu wartości, który wprowadzasz, przez co jest ono bardziej elastyczne w użyciu. 

Każde wyrażenie lambda może być przekonwertowane na delegat. Typ delegata, na który dane wyrażenie może być przekonwertowane, jest definiowany przez typy przyjmowanych parametrów i zwracanych wartości.

Jeśli wyrażenie lambda nie zwraca wartości, to można je przekonwertować na jeden z delegatów typu Action.

W innym przypadku, możliwe jest przekonwerowanie ich na jeden z delegatów typu Func. Na przykład, wyrażenie lambda, które posiada dwa parametry i nie zwraca żadnej wartości, może być przekonwertowane na delegat Action<T1,T2>.

Wyrażenie lambda, które ma tylko jeden parametr i zwraca wartość może zostać przekonwertowane na delegat Func<T,TResult>.

Oznacza to tyle, że podczas pisania metody, która traktuje wyrażenie lambda jako parametr, musimy go określić jako odpowiedni delegat. 

Przykład w kodzie

Oto, co zrobię w poniższym przykładzie:

  • Stworzę klasę Model.
  • Stworzę metodę, która wygeneruje losowe dane. Metoda ta przyjmie wyrażenie lambda jako parametr, który zdefiniuje, jak te dane będą generowane.
  • Stworzę kolejną metodę, która zmieni właściwości klasy Model. Metoda ta również przyjmie wyrażenie lambda jako parametr, który zdefiniuje sposób w jaki właściwości klasy zostaną zmienione. 


Oto jak to wygląda: 

Stworzenie klasy Model

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Stworzenie metod

public static class PersonExtensions
{
    public static void GenerateRandomName(this Person person, Func<Person> action)
    {
        var randomPerson = action();
        person.FirstName = randomPerson.FirstName;
        person.LastName = randomPerson.LastName;
    }
public static void Mutate(this Person person, Func<string, string> action)
    {
        person.FirstName = action(person.FirstName);
        person.LastName = action(person.LastName);
    }
}

Wyrażenie lambda jako parametr

Jesteśmy teraz gotowi do przeprowadzenia testu.

Poniżej znajduje się aplikacja konsolowa, która używa metod zdefiniowanych powyżej. 

using Faker;
using System;
using Workspace.Extensions;
namespace Workspace
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var randomPerson = new Person();
            randomPerson.GenerateRandomName(() =>
            {
                return new Person()
                {
                    FirstName = Name.First(),
                    LastName = Name.Last()
                };
            });
Console.WriteLine($"{randomPerson.FirstName} {randomPerson.LastName}"); // Output: Rico Wiegand
            randomPerson.Mutate(x => x.ToUpper());
            Console.WriteLine($"{randomPerson.FirstName} {randomPerson.LastName}"); // Output: RICO WIEGAND
        }
    }
}

Źródła

<p>Loading...</p>