Metody

Metoda to blok kodu, który wykonuje określone operacje i może być wielokrotnie wywoływany w programie. Metody są częścią klasy i zawierają instrukcje, które wykonują określone zadania, takie jak obliczenia, operacje na danych czy wyświetlanie informacji.

Metody pomagają:

  • Organizować kod – dzięki nim możemy podzielić program na mniejsze, logiczne części.
  • Reużywać kod – raz napisana metoda może być używana wielokrotnie, co oszczędza czas i zapobiega powtarzaniu kodu.
  • Ukrywać szczegóły implementacji – metoda wykonuje określone zadanie, ale jak dokładnie to robi, może być ukryte przed resztą programu.

Składnia metody w C#

Metoda składa się z kilku elementów:

  • Modyfikator dostępu (np. public, private) – określa, skąd metoda może być wywoływana.
  • Typ zwracany – określa, jaki typ danych metoda zwraca (np. int, string). Jeśli metoda nie zwraca żadnej wartości, używa się void.
  • Nazwa metody – unikalna nazwa metody w klasie.
  • Parametry – lista danych, które można przekazać do metody, aby metoda mogła pracować na różnych wartościach.
  • Ciało metody – blok kodu zawierający instrukcje, które metoda wykonuje.

Przykład prostej metody:

public class Kalkulator
{
    // Metoda dodająca dwie liczby
    public int Dodaj(int a, int b)
    {
        return a + b;  // Zwraca sumę liczb a i b
    }
}

Wyjaśnienie:

  • public to modyfikator dostępu – metoda jest dostępna z zewnątrz klasy.
  • int to typ zwracany – metoda zwraca liczbę całkowitą.
  • Dodaj to nazwa metody.
  • int a, int b to parametry – metoda przyjmuje dwie liczby całkowite, które będą użyte w obliczeniach.
  • return – operator, który zwraca wynik działania metody.

Wywoływanie metody

Aby skorzystać z metody, należy ją wywołać. Wywołanie metody oznacza, że uruchamiamy kod, który jest zapisany wewnątrz metody. Robimy to, podając nazwę metody wraz z odpowiednimi wartościami dla jej parametrów (jeśli są wymagane).

Przykład wywołania metody:

Kalkulator kalkulator = new Kalkulator();
int wynik = kalkulator.Dodaj(5, 3);
Console.WriteLine(wynik);  // Wypisze: 8

W tym przykładzie:

  • Tworzymy obiekt klasy Kalkulator.
  • Wywołujemy metodę Dodaj(5, 3), która dodaje liczby 5 i 3, a wynik zostaje przypisany do zmiennej wynik.
  • Metoda Dodaj zwraca wynik działania (8), który jest następnie wypisywany.

Metody z parametrami i bez parametrów

a) Metody z parametrami

Metody mogą przyjmować parametry, które są wartościami przekazywanymi do metody w momencie jej wywołania. Parametry są jak dane wejściowe dla metody – metoda może na nich operować i zwrócić wynik lub wykonać jakąś operację.

Przykład metody z parametrami:

public class Kalkulator
{
    public int Pomnoz(int a, int b)
    {
        return a * b;  // Zwraca wynik mnożenia a i b
    }
}

b) Metody bez parametrów

Jeśli metoda nie potrzebuje żadnych danych wejściowych, można ją zdefiniować bez parametrów.

Przykład metody bez parametrów:

public class Powitanie
{
    public void WyswietlPowitanie()
    {
        Console.WriteLine("Witaj w programie!");
    }
}

W tym przykładzie metoda WyswietlPowitanie() nie przyjmuje żadnych parametrów. Można ją po prostu wywołać, a wynik działania to wypisanie komunikatu na ekranie.

Metody z wartością zwracaną i bez wartości zwracanej

a) Metody z wartością zwracaną

Metody mogą zwracać wartości – oznacza to, że po zakończeniu działania metoda oddaje wynik, który można przypisać do zmiennej lub użyć w innym miejscu. Typ zwracany jest określany na początku definicji metody.

Przykład metody zwracającej wartość:

public class Kalkulator
{
    public int Odejmij(int a, int b)
    {
        return a - b;  // Zwraca różnicę a i b
    }
}

b) Metody bez wartości zwracanej (void)

Jeśli metoda nie zwraca żadnej wartości (czyli po jej zakończeniu nie ma wyniku), używamy słowa kluczowego void.

Przykład metody void:

public class Powitanie
{
    public void Powitaj()
    {
        Console.WriteLine("Witaj użytkowniku!");
    }
}

Metody statyczne

Metody mogą być statyczne. Oznacza to, że należą one do klasy, a nie do konkretnej instancji tej klasy. Aby wywołać metodę statyczną, nie musimy tworzyć obiektu klasy – możemy ją wywołać bezpośrednio, używając nazwy klasy.

Przykład metody statycznej:

public class Kalkulator
{
    public static int Dodaj(int a, int b)
    {
        return a + b;
    }
}

// Wywołanie metody statycznej
int wynik = Kalkulator.Dodaj(5, 3);
Console.WriteLine(wynik);  // Wypisze: 8

W tym przykładzie metoda Dodaj jest statyczna, więc można ją wywołać bez tworzenia obiektu klasy Kalkulator.

Przeciążanie metod

W C# możliwe jest tworzenie kilku metod o tej samej nazwie, pod warunkiem, że różnią się one liczbą lub typem parametrów. Jest to nazywane przeciążaniem metod (ang. method overloading). Przeciążanie pozwala na tworzenie bardziej elastycznych metod, które mogą działać na różnych typach danych.

Przykład przeciążania metod:

public class Kalkulator
{
    // Dodawanie dwóch liczb całkowitych
    public int Dodaj(int a, int b)
    {
        return a + b;
    }

    // Dodawanie trzech liczb całkowitych
    public int Dodaj(int a, int b, int c)
    {
        return a + b + c;
    }

    // Dodawanie dwóch liczb zmiennoprzecinkowych
    public double Dodaj(double a, double b)
    {
        return a + b;
    }
}

W tym przykładzie metoda Dodaj jest przeciążona – istnieje kilka wersji tej metody, które przyjmują różną liczbę parametrów lub różne typy danych.

Operator ref

Operator ref pozwala przekazać parametr do metody jako referencję, czyli zmienną, którą można modyfikować wewnątrz metody. Aby użyć operatora ref, zarówno w wywołaniu, jak i w definicji metody, należy to odpowiednio oznaczyć. Ważne jest, że zmienna, którą przekazujemy do metody, musi być zainicjalizowana przed wywołaniem.

Składnia z operatorem ref:

  • W definicji metody: dodajemy słowo kluczowe ref przed typem parametru.
  • W wywołaniu metody: dodajemy słowo kluczowe ref przed zmienną przekazywaną do metody.

Przykład użycia ref:

public class Kalkulator
{
    // Metoda, która zwiększa wartość parametru o 10, używając ref
    public void ZwiekszO10(ref int liczba)
    {
        liczba += 10;
    }
}

class Program
{
    static void Main()
    {
        int mojaLiczba = 5;
        Kalkulator kalkulator = new Kalkulator();

        // Przekazanie zmiennej przez ref
        kalkulator.ZwiekszO10(ref mojaLiczba);

        Console.WriteLine(mojaLiczba);  // Wypisze: 15
    }
}

Wyjaśnienie:

  • Metoda ZwiekszO10 przyjmuje parametr przez referencję, więc modyfikuje oryginalną zmienną.
  • Po wywołaniu metody zmienna mojaLiczba zmienia swoją wartość, ponieważ przekazaliśmy ją z użyciem ref.

Operator out

Operator out działa podobnie jak ref, ale jest używany w sytuacjach, gdy chcemy przekazać zmienną do metody bez wcześniejszego jej inicjalizowania. Wartość zmiennej zostanie przypisana wewnątrz metody i przekazana na zewnątrz. Przekazywana zmienna musi być zainicjalizowana wewnątrz metody przed zakończeniem jej działania.

Składnia z operatorem out:

  • W definicji metody: dodajemy słowo kluczowe out przed typem parametru.
  • W wywołaniu metody: dodajemy słowo kluczowe out przed zmienną przekazywaną do metody.

Przykład użycia out:

public class Kalkulator
{
    // Metoda, która zwraca iloraz i resztę z dzielenia, używając out
    public void Podziel(int dzielna, int dzielnik, out int iloraz, out int reszta)
    {
        iloraz = dzielna / dzielnik;
        reszta = dzielna % dzielnik;
    }
}

class Program
{
    static void Main()
    {
        Kalkulator kalkulator = new Kalkulator();
        int iloraz;
        int reszta;

        // Wywołanie metody z użyciem out
        kalkulator.Podziel(10, 3, out iloraz, out reszta);

        Console.WriteLine($"Iloraz: {iloraz}, Reszta: {reszta}");  // Wypisze: Iloraz: 3, Reszta: 1
    }
}

Wyjaśnienie:

  • Metoda Podziel używa operatora out, aby przekazać więcej niż jedną wartość na zewnątrz metody.
  • Zmienne iloraz i reszta są inicjalizowane wewnątrz metody i mogą być używane po jej wywołaniu.

Różnice między ref a out

Chociaż zarówno ref, jak i out służą do przekazywania zmiennych przez referencję, istnieją pewne kluczowe różnice:

  • ref: Zmienna musi być zainicjalizowana przed wywołaniem metody.
  • out: Zmienna nie musi być zainicjalizowana przed wywołaniem metody, ale musi być zainicjalizowana wewnątrz metody.

Zastosowania ref i out

Kiedy używać ref:

  • Kiedy chcemy przekazać zmienną do metody, aby ją zmodyfikować, i potrzebujemy zachować jej wartość między wywołaniami.
  • Kiedy metoda powinna modyfikować wartość parametru i zwrócić wynik na zewnątrz.

Kiedy używać out:

  • Gdy chcemy zwrócić więcej niż jedną wartość z metody.
  • Gdy nie potrzebujemy inicjalizować zmiennej przed przekazaniem jej do metody, a metoda będzie odpowiedzialna za jej inicjalizację.

Przykład parametru domyślnego

Załóżmy, że mamy metodę wyświetlającą powitanie. Możemy dodać parametr domyślny, który, jeśli nie zostanie podany, przyjmie domyślną wartość "Użytkowniku".

public class Powitanie
{
    // Parametr domyślny imie ma wartość "Użytkowniku"
    public void Powitaj(string imie = "Użytkowniku")
    {
        Console.WriteLine($"Witaj, {imie}!");
    }
}

class Program
{
    static void Main()
    {
        Powitanie powitanie = new Powitanie();

        powitanie.Powitaj("Jan");  // Wypisze: Witaj, Jan!
        powitanie.Powitaj();       // Wypisze: Witaj, Użytkowniku!
    }
}

Wyjaśnienie:

  • W metodzie Powitaj parametr imie ma wartość domyślną "Użytkowniku".
  • Gdy wywołamy metodę z przekazanym argumentem, np. "Jan", metoda użyje tej wartości.
  • Gdy wywołamy metodę bez argumentów, metoda użyje wartości domyślnej "Użytkowniku".

Wiele parametrów domyślnych

W metodzie możemy mieć wiele parametrów domyślnych. Ważne jest jednak, aby parametry domyślne znajdowały się na końcu listy parametrów. Wszystkie parametry przed nimi muszą być podane podczas wywołania.

Przykład z wieloma parametrami domyślnymi:

public class Kalkulator
{
    // Dodajemy domyślne wartości dla parametrów b i c
    public int Dodaj(int a, int b = 10, int c = 5)
    {
        return a + b + c;
    }
}

class Program
{
    static void Main()
    {
        Kalkulator kalkulator = new Kalkulator();

        // Przekazujemy tylko wartość dla a
        Console.WriteLine(kalkulator.Dodaj(2));      // Wypisze: 17 (2 + 10 + 5)

        // Przekazujemy wartości dla a i b
        Console.WriteLine(kalkulator.Dodaj(2, 3));   // Wypisze: 10 (2 + 3 + 5)

        // Przekazujemy wartości dla a, b i c
        Console.WriteLine(kalkulator.Dodaj(2, 3, 4)); // Wypisze: 9 (2 + 3 + 4)
    }
}

Wyjaśnienie:

  • Parametr a jest wymagany, ponieważ nie ma wartości domyślnej.
  • Parametry b i c mają wartości domyślne, więc mogą, ale nie muszą być podane podczas wywołania.

Korzyści z używania parametrów domyślnych

  • Elastyczność: Użytkownik metody może wywołać metodę, przekazując tylko te argumenty, które są mu potrzebne, a reszta zostanie automatycznie uzupełniona.
  • Mniejsza liczba przeciążeń: Zamiast tworzyć wiele wersji tej samej metody z różną liczbą argumentów, można użyć parametrów domyślnych, co upraszcza kod.
  • Czytelność: Wartości domyślne mogą jasno pokazywać, jakie są „standardowe” zachowania metody.

Wymagania dotyczące parametrów domyślnych

  • Parametry domyślne muszą być umieszczone na końcu listy parametrów. Nie można mieć parametrów bez wartości domyślnej po tych, które mają wartości domyślne.

Niepoprawny przykład:

public void ZlyPrzyklad(int a = 1, int b)
{
    // Nie można umieścić parametru z wartością domyślną przed parametrem bez domyślnej wartości
}

Powyższy przykład spowoduje błąd kompilacji, ponieważ parametr a ma wartość domyślną, ale b jej nie ma. Parametry z wartościami domyślnymi muszą być na końcu.

Parametry domyślne a przeciążanie metod

Parametry domyślne nie wykluczają przeciążania metod. Możemy przeciążać metody i jednocześnie korzystać z parametrów domyślnych. Ważne jest jednak, aby C# był w stanie jednoznacznie określić, którą wersję metody wywołać.

Przykład przeciążania i parametrów domyślnych:

public class Powitanie
{
    // Pierwsza metoda z jednym parametrem domyślnym
    public void Powitaj(string imie = "Użytkowniku")
    {
        Console.WriteLine($"Witaj, {imie}!");
    }

    // Przeciążona metoda bez parametrów
    public void Powitaj()
    {
        Console.WriteLine("Witaj!");
    }
}

class Program
{
    static void Main()
    {
        Powitanie powitanie = new Powitanie();

        powitanie.Powitaj("Anna");  // Wypisze: Witaj, Anna!
        powitanie.Powitaj();        // Wypisze: Witaj!
    }
}

W tym przypadku mamy dwie różne metody Powitaj – jedna bez parametrów i druga z jednym parametrem, który ma wartość domyślną. Dzięki przeciążaniu można wywołać metodę w różnych scenariuszach.