Nauka wykorzystywania delegatów jako bezpiecznych typowo wskaźników na metody oraz zrozumienie idei przekazywania zachowania jako parametru (callback). Student pozna wbudowane typy delegatów (Func, Action), metody anonimowe oraz wyrażenia lambda, które znacząco skracają i unowocześniają kod C#.
Pracownicy Twojego komisu "Auto-Premium" codziennie mierzą się z dziesiątkami specyficznych zapytań od potencjalnych kupców. Jeden szuka wyłącznie tanich aut do 15 tys. zł, inny interesuje się tylko markami luksusowymi, a jeszcze inny chce zobaczyć wszystkie pojazdy wyprodukowane w ciągu ostatnich trzech lat. Pisanie oddzielnych metod dla każdego z tych warunków sprawiłoby, że Twój system stałby się niezarządzalną, powtarzalną plątaniną kodu.
Rozwiązaniem są delegaty – fundament programowania funkcyjnego w C#. Pozwalają one na traktowanie metod jak zwykłych zmiennych. Dzięki temu możesz stworzyć jedną, uniwersalną "wyszukiwarkę", która jako parametr przyjmuje nie wartość, a "logikę wyboru" (warunek filtrowania). W połączeniu z wyrażeniami lambda (skróconym zapisem metod), Twoje zapytania stają się tak zwięzłe, że filtrujesz plac komisu jedną czytelną linijką kodu. To technika, która otwiera drzwi do zaawansowanych bibliotek takich jak LINQ i sprawia, że Twój system jest gotowy na najbardziej wymyślne prośby klientów.
using System;
using System.Collections.Generic;
namespace LaboratoriumOOP
{
public class Pojazd
{
public string Marka { get; set; }
public double Cena { get; set; }
public int Rok { get; set; }
}
class Program
{
// DELEGAT: Typ określający "sygnaturę" metody, którą możemy tu podstawić.
// Mówi: "przyjmę każdą metodę, która bierze Pojazd i zwraca bool".
public delegate bool WarunekPojazdu(Pojazd p);
static void Main(string[] args)
{
Console.WriteLine("--- ZADANIE 09: Delegaty i lambdy ---\n");
List<Pojazd> komis = new List<Pojazd>
{
new Pojazd { Marka = "Skoda", Cena = 12000, Rok = 2012 },
new Pojazd { Marka = "BMW", Cena = 150000, Rok = 2022 },
new Pojazd { Marka = "Fiat", Cena = 8000, Rok = 2005 },
new Pojazd { Marka = "Audi", Cena = 45000, Rok = 2016 }
};
// 1. Użycie delegata z METODĄ NAZWANĄ
Console.WriteLine("Pojazdy tanie (filtr metodą nazwaną):");
WyswietlFiltrowane(komis, CzyTani);
// 2. Użycie delegata z WYRAŻENIEM LAMBDA
// Lambda to skrócona, anonimowa metoda: (parametry) => wyrażenie
Console.WriteLine("\nPojazdy po 2015 roku (filtr lambdą):");
WyswietlFiltrowane(komis, p => p.Rok > 2015);
// 3. Użycie wbudowanego delegata Func
double limitBudzetu = 50000;
Console.WriteLine($"\nPojazdy w budżecie {limitBudzetu} PLN (Func + closure):");
// Lambda "zamyka" (przechwytuje) zmienną limitBudzetu z otoczenia
List<Pojazd> wyniki = FiltrujZFunc(komis, p => p.Cena <= limitBudzetu);
wyniki.ForEach(p => Console.WriteLine($"- {p.Marka}"));
// 4. Delegat wielopunktowy (Multicast)
Console.WriteLine("\nWykonanie serii akcji na obiekcie (Action multicast):");
Action<Pojazd> operacjeLoggera = p => Console.Write($"[LOG] Analiza: {p.Marka}... ");
operacjeLoggera += p => Console.WriteLine("Status: OK");
operacjeLoggera(komis[0]);
Console.ReadKey();
}
// Metoda przyjmująca delegat jako parametr (Callback)
static void WyswietlFiltrowane(List<Pojazd> lista, WarunekPojazdu filtr)
{
foreach (var p in lista)
{
if (filtr(p)) Console.WriteLine($"- {p.Marka} ({p.Rok})");
}
}
// Nowocześniejsza wersja z Func
static List<Pojazd> FiltrujZFunc(List<Pojazd> lista, Func<Pojazd, bool> filtr)
{
List<Pojazd> wynik = new List<Pojazd>();
foreach (var p in lista)
{
if (filtr(p)) wynik.Add(p);
}
return wynik;
}
static bool CzyTani(Pojazd p) => p.Cena < 15000;
}
}