Metoda je pojmenovaný blok kódu, který vykonává určitou logiku. V .NET (a obecně v programování) slouží k:

  • zapouzdření opakovaného kódu
  • zjednodušení programu na menší logické celky
  • znovu použitelnosti logiky
  • organizaci kódu (lepší čitelnost a údržba)

Metoda vs. Funkce

Metoda Blok kódu, který je umístěn v rámci třídy.

Funkce Blok kódu, který je nezávislý na třídě. Jako funkce se v C# označují delegáty Func<>.

Vstupním bodem každého C# programu je metoda Main.

private static void Main(string[] args) { }

Struktura metody

Ukázka metody

public int Add(int a, int b)
{
    return a + b;
}

Vysvětlení

  • hlavička metody
    • public → modifikátor přístupu
    • int → návratový typ
      • Pokud metoda nic nevrací, tak se využívá klíčové slovo void
    • Add → název metody
    • (int a, int b) → parametry metody
  • tělo metodyreturn a + b;

Parametr vs. Argument metody

  • Parametr = proměnná definovaná v deklaraci (hlavičce) metody.
  • Argument = hodnota, která se parametru předává při volání metody.
void PrintMessage(string message) // message je parametr
{
    Console.WriteLine(message);
}
 
PrintMessage("Hello!"); // "Hello!" je argument

Dělení parametrů

Parametry metod lze dělit na:

  1. Vstupní parametry
  2. Výstupní parametry
  3. Vstupně výstupní parametry

Výchozím typem parametru je vstupní parametr (in klíčové slovo, které se nemusí psát). Změnu typu parametru lze realizovat napsáním příslušného klíčového slova před datový typ parametru.

1. Vstupní parametry

Nejběžnější způsob – parametry se do metody pouze předávají.

public void Greet(string name)
{
    Console.WriteLine($"Hello, {name}!");
}
 
// Explicitně pak takhle, ale nepoužívá se:
public void Greet(in string name)
{
    Console.WriteLine($"Hello, {name}!");
}
 
 
// Volání
Greet("Alice");

2. Výstupní parametry – out

Metoda vrací hodnotu přes parametr. Parametr nemusí mít hodnotu před voláním. Tento typ parametrů je velmi využíván pro bezpečné parsování vstupu - např. int.TryParse(input, out int result), kde metoda vrací true/false dle toho, jestli se povedlo zparsovat vstup. Samotný výsledek parsování je pak přítomný v druhém parametru.

Před opuštěním metody je nutné výstupnímu parametru nastavit hodnotu.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}
 
public class UserRepository
{
    private List<User> _users = new List<User>
    {
        new User { Id = 1, Name = "Alice" },
        new User { Id = 2, Name = "Bob" }
    };
 
    public bool TryGetUserById(int id, out User user)
    {
        user = _users.FirstOrDefault(u => u.Id == id);
        return user != null;
    }
}

3. Vstupně-výstupní parametry – ref

Metoda používá aktuální hodnotu parametru a může ji změnit. Hodnota musí být inicializována před voláním. Změna hodnoty v metodě ovlivní hodnotu i ve volajícím.

void MultiplyByTwo(ref int number)
{
    number = number * 2;
}
 
int num = 5;
Console.WriteLine(num); // 5
MultiplyByTwo(ref num);
Console.WriteLine(num); // 10

Extension metody (Rozšiřující metody)

Rozšiřující (extension) metody umožňují rozšiřovat funkcionalitu již existujících typů, aniž by bylo nutné je měnit nebo z nich dědit. Typicky se využívají pokud je potřeba do již existujícího typu, kde není možné měnit zdrojový kód, přidat nějakou vlastní logiku (např. metodu).

Fungování

  • Musí být definované ve statické třídě.
  • Samotná metoda musí být statická.
  • První parametr je speciální – začíná klíčovým slovem this.
    • Říká, který typ se rozšiřuje.

Ukázka

Metoda, která zjistí, jestli je string číslo v rozsahu datového typu int.

public static class StringExtensions
{
    public static bool IsNumeric(this string input)
    {
        return int.TryParse(input, out _);
    }
}

Ukázka použití:

string value = "12345";
bool result = value.IsNumeric(); // true
Console.WriteLine(result);

Přetěžování metod

Metody se mohou přetížit (více informací v Polymorfismu na stránce o Polymorfismu, tj. mít stejný název, ale různé parametry:

public void Print(string message)
{
    Console.WriteLine(message);
}
 
public void Print(int number)
{
    Console.WriteLine(number);
}

Rekurze

Rekurze znamená, že funkce (nebo metoda) volá sama sebe, aby vyřešila podproblém původního problému. Tedy například problém sečtení tří čísel lze rozpadnout na dva menší problémy sečtení dvou čísel.

Převod rekurze na iteraci a obráceně

Platí, že každou iteraci (cykly) lze převést na rekurzi a obráceně.

Rekurze musí vždy obsahovat

Podmínka ukončení (base case)

  • říká, kdy se rekurze má zastavit
  • chrání před nekonečným voláním funkce
  • pokud tato podmínka chybí, tak programy končí zpravidla StackOverflowException - přetečením zásobníku, jelikož každé volání metody na zásobníku tvoří nový záznam s parametry metody

Rekurzivní volání (recursive case)

  • část, kde funkce volá sama sebe s jinými (menšími) vstupními hodnotami

Jednoduchá ukázka - Faktoriál

Faktoriál je definován rekurzivně:

public int Factorial(int n)
{
    if (n == 0)
        return 1;                    // Base case
 
    return n * Factorial(n - 1);     // Recursive case
}

Typy rekurze

  • Přímá rekurze - metoda volá přímo sama sebe
    • Např.: Faktoriál
  • Nepřímá rekurze - Metoda nevolá sama sebe přímo, ale zprostředkovaně přes jiné metody.

Ukázka nepřímé rekurze:

public void MethodA(int n)
{
    if (n <= 0)
        return;
 
    Console.WriteLine("A");
    MethodB(n - 1);
}
 
public void MethodB(int n)
{
    if (n <= 0)
        return;
 
    Console.WriteLine("B");
    MethodA(n - 1);
}

Kdy rekurzi používat?

Rekurze je skvělá pro problémy, které mají přirozenou hierarchickou nebo opakující se strukturu, např.:

  • průchody stromů (DOM, souborové systémy)
  • algoritmy pro kombinace, permutace
  • matematické výpočty (faktoriál, Fibonacciho čísla)
  • řešení úloh typu divide and conquer (quicksort, mergesort)