W kolejnym materiale z cyklu języka C# przedstawię jedną z prostych, acz potężnych konstrukcji mogących znacznie podnieść jakość kodu źródłowego 📈! Poznasz czym w języku C# jest "Action", w jaki sposób się z tego korzysta i dlaczego warto to stosować! Zapraszam po szczegóły 😊!

"ACTION" W JĘZYKU C# KONSTRUKCJĄ NA WAGĘ ZŁOTA!

Na samym starcie zaznaczę, iż temat ma związek z delegatami i typami generycznymi, więc warto się z nimi zapoznać w pierwszej kolejności, zanim spróbujesz zrozumieć ten wątek ⚠️.

Zaczniemy od przedstawienia samego "cosia" jakim jest "Action", następnie przejdziemy do ukazania stosowania go w kodzie, a całość materiału skończymy prostym przykładem użycia 👍.

Czym jest "Action" w języku C#?

W C#, "Action" oznacza formalnie alias delegata metody niezwracającej żadnej wartości (typ "void"). Ujmując to łatwiejszym do zrozumienia językiem, jest to miejsce do zdefiniowania (czy wskazania) metody niezwracającej wartości, jaka ma zostać wykonana w późniejszym toku działania programu (np. po ukończeniu jakiegoś zadania) 🌟. Taka metoda do wykonania może przyjmować własne parametry, tak jak każda inna metoda! "Action" składa się aż z 17 różnych postaci wyróżniających się liczbą typów generycznych (od 0 do 16), więc na pewno nikomu nie zabraknie na nie miejsca 😁!

Często stosowaną praktyką jest umieszczanie "Action" jako parametr metody i to wtedy oznacza możliwość dosłownego wstawienia instrukcji do wykonania w formie bloku kodu podczas wywoływania metody, a te instrukcje mogą być inne przy każdym osobnym wywołaniu (działa jak taki "element wymienny") 🤩! To jest największa zaleta stosowania "Action", dzięki której podnosi się elastyczność tej metody i skutecznie redukuje powtarzalność kodu ❤️! Z tego powodu uważam ten temat za jeden z najcenniejszych jaki warto opanować 🔥!

"Action" jest równoważny następującemu zapisowi delegata w sposób tradycyjny 👇:

delegate void MyDelegate([opcjonalne parametry]);

"Action" jest jednym z dwóch słówek w języku C# związanych z uprzednio przygotowanymi delegatami jakie warto znać. Drugie hasło to "Func", które jest przeznaczone dla metod zwracających jakąś wartość (więcej informacji znajdzie się w odrębnym artykule).

To tyle z teorii, więc teraz przyjrzymy się jak z tego korzystać 👀!

Jak skorzystać z "Action" w języku C#?

Musimy sobie rozbić ten rozdział na 2 osobne części, gdyż diametralnie różnią się od siebie 👇:

  1. definicja metody przyjmującej typ "Action",
  2. wywoływanie metody przyjmującej typ "Action".

Teraz pokażę jak to zastosować w praktyce dla obu przypadków!

Jak skorzystać z "Action" w języku C# podczas definiowania metody?

Gdy zechcesz utworzyć metodę mającej przyjmować parametr typu "Action", wystarczy w miejsce parametru podać typ "Action" i wstawić nazwę parametru, tak jak zwykle ✔️. Najprostsza postać może wyglądać w taki sposób 👇:

void DoSomething(Action action)
{
	// instrukcje
}

To jeszcze nie jest wszystko. Gdy mamy wstawione "Action" jako parametr, to to oznacza "miejsce" dla metody typu "void", aczkolwiek to nie jest jednoznaczne z natychmiastowym wywołaniem tejże metody! Musimy dopisać sobie to wywołanie stosując ten sam znany zapis 👇:

void DoSomething(Action action)
{
	// instrukcje
	
	action();
	
	// instrukcje
}

To będzie znaczyło, że po wprowadzeniu metody (czyli instrukcji do wykonania), zostanie ona wywołana dopiero wtedy, gdy program natrafi na taką instrukcję ⏩! Czyli będziemy mieli taką sytuację 👇:

  1. instrukcje wykonują się jedna po drugiej,
  2. następuje wywołanie metody z parametru typu "Action" (wywoływanie metody jest chwilowo wstrzymane),
  3. po zakończeniu wszystkich instrukcji metody z parametru typu "Action", jest wznawiana obecna metoda i wykonywanie pozostałych instrukcji (jeśli jeszcze jakieś występują).

Jeżeli metoda ma posiadać parametr, to należy go dopisać jako typ generyczny wewnątrz nawiasów kątowych, tuż po słowie "Action" 👇:

void DoSomething(Action<int> action)

To jest przykład z dodanym parametrem typu "int", co oznacza że w miejsce parametru "Action" będzie można umieścić metodę wyłącznie przyjmującą jeden parametr typu całkowitoliczbowego.

C# dysponuje aż siedemnastoma różnymi odmianami typu "Action", które różnią się liczbą przyjmowanych parametrów od zera do szesnastu i właśnie nimi posługujemy się do określenia ile parametrów metoda powinna akceptować 🙂.

Trzeba być świadom jednego ważnego szczegółu: parametr typu "Action" tak jak każdy inny, może przyjąć wartość "null" 💥! A to znaczy, że próba wywołania metody której nie ma, spowoduje zgłoszenie wyjątku i przerwanie programu jeśli nie zostanie obsłużony 🚫!

Jak zabezpieczyć się przed wartością "null" dla typu "Action" w języku C#?

Należy po prostu dodać instrukcję warunkową sprawdzającą czy parametr nie przyjmuje wartości "null" 👇:

if(action != null)
{
	action();
}

Dużo prostszym zapisem jest połączenie operatora sprawdzającego wartość "null" z metodą "Invoke" ☟:

action?.Invoke();

Używając jednego z dwóch sposobów, zabezpieczamy się przed przypadkiem braku metody do wywołania 👍.

To wszystko na temat definiowania metody z użyciem typu "Action" ✅. Przechodzimy zatem do drugiej części, czyli jak to wygląda od strony wywoływania metody!

Jak skorzystać z "Action" w języku C# podczas wywoływania metody?

W sytuacji, gdy chcemy wywołać metodę, która przyjmuje parametr typu "Action" 👇:

void DoSomething(Action action)

to są 2 metody przekazywania "wartości" (którym w tym wypadku jest wskaźnik do metody, czyli delegat!) 👇:

  1. wyrażenie lambda (funkcja anonimowa),
  2. referencja do metody.

Wyrażenie lambda to blok kodu osadzony bezpośrednio w miejsce parametru metody "Action", co oznacza że te instrukcje dotyczą tylko tego konkretnego wywołania i żadnego innego 👇:

DoSomething(() => [instrukcje]);

Wyrażenia lambda zostały opisane w osobnym artykule ℹ️.

Referencja do metody to drugi sposób polegający na tym, że w miejsce parametru metody "Action" wpisujemy nazwę metody występującej w innym miejscu w kodzie. Zakładając, że mielibyśmy taką metodę w tym samym pliku źródłowym 👇:

void MyMethod()
{
	// instrukcje
}

to wówczas możemy przekazać tę metodę do wywołania poprzez "Action" pisząc w taki sposób (przy założeniu, że w pełni zgadzają się ze sobą nagłówki metod) 👇:

DoSomething(MyMethod);

W obu przypadkach aby doszło do prawidłowego obsłużenia parametru, musi zachodzić 100% zgodność z nagłówkiem metody, czyli typ zwracanej wartości oraz lista parametrów (i w liczbie, i w typach) ⚠️!

Na tym kończę część związaną z wywoływaniem metody przyjmującej parametr typu "Action" ✅, więc na deser krótki przykład użycia 🚀!

Przykład użycia "Action" w języku C#

Przykład dotyczyć będzie utworzenia sobie metody, która przyjmuje liczbę całkowitą oraz parametr pozwalający na przekazanie metody do wywołania również akceptującej liczbę całkowitą, tak aby dwukrotne wywołanie tej samej metody umożliwiało wstawienie dwóch różnych bloków instrukcji na podanej liczbie 🧩.

W C#, możemy to zrealizować w następujący sposób 👇:

public static void Main()
{
	int number = 20;
			
	InvokeActionOnNumber(number, n => Console.WriteLine("Wprowadzono liczbę " + n));
	InvokeActionOnNumber(number, WriteNumberAsBinary);
}

private static void InvokeActionOnNumber(int number, Action<int> action)
{
	Console.WriteLine("Wykonuję podaną metodę");
	action?.Invoke(number);
}

private static void WriteNumberAsBinary(int number)
{
	Console.WriteLine(number + " w systemie dziesiętnym jest równe " + Convert.ToString(number, 2) + " w systemie dwójkowym");
}

Prześledźmy wszystkie metody po kolei 🔍!

W metodzie uruchomieniowej "Main" mamy liczbę całkowitą, która zostanie wprowadzona do dwóch osobnych wywołań metody umożliwiającej dodanie dowolnych instrukcji do wykonania z jej udziałem. Niżej znajdują się wspomniane wywołania i do pierwszego z nich jest dodana metoda z jedną instrukcją wypisującą podaną liczbę (używając wywołania metody "WriteLine") w formie wyrażenia lambda, a do drugiego wstawiona nazwa metody zdefiniowanej na zewnątrz (referencja do metody).

Kolejna metoda jest tą wykonującą określone operacje z użyciem liczby całkowitej 🔥. Przyjmuje parametr typu "int" oraz "Action". Ponieważ chcemy, aby metoda w miejscu "Action" opierała się na podanej liczbie całkowitej, dodajemy do niego typ generyczny "int" określając to jako metodę akceptującą jeden parametr typu całkowitoliczbowego 💡! W jej środku mamy wypisanie wiadomości o wykonywaniu metody parametru "Action" przy użyciu wywołania metody "WriteLine", a zaraz po nim wywoływanie podanej metody z użyciem operatora zabezpieczającego przed wartością "null".

Ostatnia z metod dotyczy drugiego wywołania metody z liczbą całkowitą i tu dla przykładu wypisujemy podaną liczbę w systemie dwójkowym, co akurat w C# możemy łatwo uzyskać stosując metodę "ToString" z klasy "Convert" poprzez podanie w drugim parametrze podstawę równą 2 ❤️!

Gdy skompilujesz i uruchomisz sobie ten program, ujrzysz w konsoli komunikaty zgodne z kolejnością wypisania poprzez oba wywołania ☑️. Najpierw wyświetli się wiadomość o rozpoczęciu wykonywania wskazanej w parametrze metody, potem osobna treść pochodząca od samej metody i następnie drugi raz to samo w tej samej kolejności 😄!

"Action" w języku C# jako parametr metody

"Action" w języku C# jest aliasem delegata przeznaczonego dla metod niezwracających żadnej wartości ("void").


Dotarliśmy do końca artykułu. Materiał powinien w sposób wyczerpujący tłumaczyć zastosowanie słowa "Action" w języku C# 😉!

PODOBNE ARTYKUŁY