Jak już wiemy z poprzedniej części funkcja może przyjmować parametry. Mogą być one dowolnego typu. Można także określić sposób przekazywania parametru. Zobaczmy przykład:

class Program {
    static void Main() {
        int i=1;
        Console.WriteLine("Wartość zmiennej i:{0}",i );
        ZmienWartosc(i);
        Console.WriteLine("Wartość zmiennej i po wykonaniu procedury:{0}", i);
        Console.ReadLine();
    }

    public static void ZmienWartosc(int a) {
        a = 19;
    }
}

Rezultat działania aplikacji:

Parametry

Rys. Wyświetlenie wartości zmiennej o nazwie i

Jak widzimy, wartość zmiennej nie uległa zmianie, ponieważ przekazujemy wartość zmiennej poprzez wartość.
Innym sposobem przekazywania zmiennej o typie wartościowym jest przekazywanie referencji na nią wskazującej.

Zobaczmy przykład:

 class Program {
    static void Main() {
        int i=1;
        Console.WriteLine("Wartość zmiennej i:{0}",i );
        ZmienWartosc(ref i);
        Console.WriteLine("Wartość zmiennej i po wykonaniu procedury:{0}", i);
        Console.ReadLine();
    }

    public static void ZmienWartosc(ref int a) {
        a = 19;
    }

}

Rezultat działania aplikacji:

Parametry

Rys. Wyświetlenie wartości zmiennej o nazwie i

Poprzez zastosowanie słowa kluczowego ref przy definicji i przy wywołaniu parametru została przekazana referencja wskazująca na zmienną typu int . Dlatego jej wartość uległa zmianie.

Ref dla typów referencyjnych

Często można spotkać się z twierdzeniem ”obiekty są przekazywane domyślnie przez referencje”. Jest ono błędne ponieważ, kiedy typ referencyjny zostanie użyty do utworzenia parametru metody, argument przekazywany jest domyślnie przez wartość a tą wartością jest referencja. Zobaczmy prosty przykład:

    class Program{
        static void Main(){
            var person = new Person { Name = "Darek" };
            SuperMethod(person);
            Console.WriteLine(person.Name);
            Console.ReadKey();
        }

        private static void SuperMethod(Person p) {
            p = null;
        }
    }

    public class Person{
        public string Name;
    }
}

Po uruchomieniu programu zobaczymy:

Rys. Wyświetlona wartość Name obiektu typu Person

Jeżeli przekazana by została bezpośrednio referencja a nie jej kopia to po przypisaniu wartości null nie powinno być już dostępu do obiektu wskazywanego przez tą referencję poza ciałem metody.

Używając słowa kluczowego ref do utworzenia parametru metody, argument przekazywany będzie bezpośrednio referencją a nie jej kopią.
Zobaczmy przykład:

      static void Main(){
            var person = new Person{Name = "Darek"};
            SuperMethod(ref person);
            Console.WriteLine(person.Name);
            Console.ReadKey();
        }

        private static void SuperMethod(ref Person p){
            p = null;
        }

Po uruchomieniu programu zobaczymy:

Rys. Wyjątek

Zwrócony został wyjątek ponieważ przekazaliśmy bezpośrednio referencję a nie jej kopię do metody SuperMethod. Przez co zmienna referencyjna person przestała wskazywać na obiekt utworzony przed wywołaniem tej metody.

Więcej niż jedna wartość zwracana

Jak wiemy z procedury, możemy zwrócić za pomocą słowa kluczowego return jedną wartość danego typu. Jednak istnieje możliwość zwrócenia w metodzie więcej niż jednej wartości zobaczmy prosty przykład:

 public static void ProcTest(int a, int b, out int sum, out int roz) {
        sum = a + b;
        roz = a - b;
    }

Używając słowa kluczowego out określamy wartości, których parametrów mają zostać zwrócone. Zobaczmy jak wywołać taką metodę z większą liczbą zwracanych wartości:

Parametry

Rys. Podpowiedz Visual Studio

Jak widzimy do metody ProcTest musimy podać dwa parametry wejściowe oraz dwa wyjściowe. Zatem potrzebujemy dwóch dodatkowych zmiennych, które przechowają wartości zwracane przez funkcję:

class Program {
    static void Main() {
        int suma, roznica;
        ProcTest(5, 1, suma, roznica);
        Console.WriteLine("Suma wynosi {0} roznica {1}", suma,roznica);
        Console.ReadLine();
    }

    public static void ProcTest(int a, int b, out int sum, out int roz) {
        sum = a + b;
        roz = a - b;
    }

}

Przy takim wywołaniu funkcji kompilator zgłasza błąd:

Parametry

Rys. Błędy zgłoszone przez kompilator.

Podczas wywołania funkcji, które zwracają więcej niż jedną wartość także musimy użyć słowa kluczowego out. Poprawmy program i zobaczmy jak działa:

class Program {
    static void Main() {
        int suma, roznica;
        ProcTest(5, 1, out suma, out roznica);
        Console.WriteLine("Suma wynosi {0} roznica {1}", suma,roznica);
        Console.ReadLine();
    }

    public static void ProcTest(int a, int b, out int sum, out int roz) {
        sum = a + b;
        roz = a - b;
    }

}

Rezultat działania aplikacji:

Parametry

Rys. Efekt działania aplikacji

Dzięki zastosowaniu słowa kluczowego out procedura zwróciła dwie wartości.

Do funkcji możemy przekazać tablicę parametrów za pomocą słowa kluczowego params. Zobaczmy przykład:

public static void ProcTest(params int[] liczby) {
        Console.WriteLine("Jest {0} elementów", liczby.Length);
        foreach(int item in liczby){
            Console.WriteLine(item);        
        }
    }

Dzięki temu możemy wywołać procedurę ProcTest() na kilka sposobów:

class Program {
    static void Main() {
        int[] tab = new int[] {0,1,2,3,4 };
        int a=8;
        int b=10;
        int c= 11;
        Console.WriteLine("Wywołanie procedury bez parametru:");
        ProcTest();
        Console.WriteLine("Wywołanie procedury z tablicą jako parametr:");
        ProcTest(tab);
        Console.WriteLine("Wywołanie procedury z trzema zmiennymi typu int jako parametr:");
        ProcTest(a,b,c);
        Console.WriteLine("Wywołanie procedury z jendą zmienną typu int jako parametr:");
        ProcTest(a);
        Console.WriteLine("Wywołanie procedury z pięcioma liczbami jako parametr");
        ProcTest(1,2,3,4,5);

        Console.ReadLine();
    }

    public static void ProcTest(params int[] liczby) {
        Console.WriteLine("Tablica ma elementów:  {0}", liczby.Length);
        foreach(int item in liczby){
            Console.WriteLine(item);        
        }
    }

}

Rezultat działania aplikacji:

Parametry

Rys. Wywołania procedury z różnymi parametrami

Dzięki zastosowaniu słowa kluczowego params funkcja może przyjmować tablicę parametrów. Dzięki temu mogę wywołać daną procedurę z dowolną ilością parametrów. Należy jednak pamiętać, że procedura może przyjmować tylko jedną tablicę parametrów :

public static void ProcTest(params int[] liczby, params double[] liczby2) {
    }

Kompilator zgłosi nam następujący błąd:

Parametry

Rys. Błąd zgłoszony przez kompilator.

Tablica parametrów musi być ostatnim z parametrów w danej procedurze, zobaczmy przykład:

public static void ProcTest(params int[] liczby, string a) {
    }

Kompilator zgłosi nam następujący błąd:

Parametry

Rys. Błąd zgłoszony przez kompilator.

Podsumowanie:
Przesyłanie parametru do procedury jako referencja, większa ilość wartości zwracanych oraz przesyłanie tablicy parametrów to bardzo przydatne opcje. Polecam się z nimi zapoznać, a za pewien czas wrócić do tego wpisu aby odświeżyć sobie zawartą w nim wiedzę.