Ref i OutCzęść NR.5Zastanawiałeś się nad tym co się dzieje ze zmiennymi, gdy wysyłasz je jako parametr do metody. Otóż parametry otrzymywane przez metody są kopiami. Czyli działanie metody nie wpłynie na wysłaną zmienną, ponieważ metoda operuje na kopii.

Nie ma znaczenia czy parametr jest typu int, float, string czy referencją on się nie zmieni. Oto przykład:

 

Cuboid cuboid = new Cuboid(1, 2, 3);
string napis = "Ala ma kota";
int liczba = 121;
NieZmienie(cuboid,liczba,napis);
Console.ReadLine();
static void NieZmienie(Cuboid cuboid,int liczba,string napis)
{
    cuboid = new Cuboid(44, 555, 666);
    liczba--;
    napis = "1234567890qwertyuiopasdfghj";
}

Rezultat działającego kodu po skończonej metodzie.

Metod-kopiuje-zmienne_thumb2
Jak widać jest tak, jak mówię.

W trakcie wykonywania metody wydaje się ,że zmienne rzeczywiście ulegają zmianie ,ale tak nie jest. W czasie debugowania kodu zmienne o tej samej nazwie są przedstawiane zależnie od kontekstu wykonywania.

Zmienne-w-trakcie-wykonywania-metody[1]
Metoda może zmienić argument obiekt, do którego się metoda referuje ,ale metoda nie może zmienić referencji do obiektu. Co to dokładnie znaczy? Znaczy to ,że mogę zmienić zawartość pól klasy Cuboid. Aby udowodnić to tymczasowo zmieniłem modyfikator dostępu pól klasy Cuboid z prywatnych na publiczne co jest złą praktyką.

public static void ZmienieZawartośćObiektu(Cuboid cu)
{
    cu.a = 12;
    cu.b = 21;
    cu.h = 33;
}
Cuboid cu = new Cuboid(1,1,1);
ZmienieZawartośćObiektu(cu);
Powyższy metoda zmieni zawartość obiektu .Jak to jest możliwe? Jeśli dobrze pamiętasz poprzednią część kursu to wiesz ,że kopiując typ referencyjnym kopiujemy tak naprawdę jej adres. Adres nie może być zmieniony wewnątrz metody ,ale sprawa wygląda inaczej dla elementów, do których ten adres się referuję, ponieważ one nie są kopiami. Co oznacza ,że mogą one trwale ulec zmianie.
 
Tak wygląda zachowanie zmiennych typów wartościowych i typów referencyjnych.

W większości wypadków to zachowanie jest całkowicie prawidłowe. Jednak czasami chcemy napisać metodę, która rzeczywiście zmieni nasze podane argumenty. W C# mamy do dyspozycji słowa kluczowe ref i out do tego celu.

Ref

Jeśli dopiszesz do parametru słowo kluczowe ref ,parametr stają się rzeczywiście tylko aliasem do metody. Czyli jakakolwiek jego zmiana w metodzie zostanie zachowana na zawsze. Dzieje się tak, ponieważ parametr w metodzie jest referencją do tego samego obiektu ,a nie kopii. Oto przykład tej samej metody “NieZmienie” tylko tym razem ona zmieni wartości na stałe. Może więc lepiej nazwać ją “Zmienie”.

static void Zmienie(ref Cuboid cuboid, ref int liczba, 
ref string napis)
{
    cuboid = new Cuboid(44, 555, 666);
    liczba--;
    napis = "1234567890qwertyuiopasdfghj";
}<

Słowo kluczowe ref też musi wystąpić przy wysłaniu parametrów do metody. Dobrze wiedzieć jak dana metoda zadziała i co robi z parametrami ,skoro nie mam wyboru i muszę użyć słowa kluczowego ref.

Cuboid argcuboid = new Cuboid(1, 2, 3);
string argnapis = "Ala ma kota";
int argliczba = 121;
Zmienie(ref argcuboid, ref argliczba, ref argnapis);

Zmieniłem nazwy zmiennych aby uświadomić, że w tym przypadku zmienna “argliczba” i parametr" “liczba” w metodzie referują się do tego samego obiektu.

REF-sowo-kluczowe_thumb2
Pamiętaj, że zmienne, zanim wyślesz je do metody muszą mieć przypisane wartości.

Słowo kluczowe out

W metodzie z parametrem ref, parametr musi mieć przypisaną wartość, zanim zostanie wywołana metoda. Może jednak chciałbyś, by metoda operowana na niezainicjowanej zmiennej i ją zmieniła. Właśnie do tego celu służy słowo kluczowe “out”.

Słowo kluczowe out w działaniu jest zbliżone do ref. Argument jest aliasem dla parametru metody.

Kiedy tworzysz metodę z parametrem out. Pamiętaj aby w trakcie działania metoda przypisała parametrowi out jakąś domyślną wartość w jakimkolwiek ciągu operacji wewnątrz metody. Jednym słowem parametr zawsze musi wrócić z przypisaną wartością.

out parametr

Zawsze.

static void Zmienie2(out int liczba)
{
    liczba = 121;
}
int f;
Zmienie2(out f);

Przykładem metody, gdzie wstępują parametry out jest np. metoda int.TryParse().Znasz metodę Parse(), która zmienia łańcuch znaków na liczbę. Metoda ta najpierw sprawdza, czy dany łańcuch może być zmieniony na liczbę , a potem przypisuje do niej wartość.

TryPARSE_thumb2

int eee;
string li = Console.ReadLine();
int.TryParse(li,out eee);
Console.WriteLine(eee);

Powyższy kod sprawdza działanie tej metody w praktyce i jej działanie na pewno nie wyrzuci żadnego wyjątku, w przeciwieństwie do int.Parse().

Sprawdziłem tę metodę. Jeśli string jest liczbą, to zmienna ma przypisaną wartość z łańcucha znaków. Jeśli metoda nie była w stanie zmienić napisu na cyfrę zmienna równa się zero.